Julich tutorial: Developing CVs in plumed

Aims

The aim of this tutorial is to introduce users to the tutorials in the developer manual of PLUMED. We will learn a little bit about the structure of the code and how this structure can be visualised using the tree diagrams in the developer manual. You will then learn how to implement a new collective variable in a way that uses as much of the functionality that is already within the code and that thus avoids the duplication of code. Finally, you will learn how to write regression tests and how these can be used for continuous integration.

Learning Outcomes

By the end of this session you will know how to:

  • access the developer manual for PLUMED.
  • find the tutorial information for implementing new collective variables, multicolvars, functions, biases and analysis routines.
    - find the tree diagrams showing the class structure in the PLUMED developer manual.
  • exploit the functionality within PLMD::multicolvar in order to write a reasonably complex collective variable quickly.
  • write regression tests for PLUMED and understand how these are used for continuous integration.

To do this module you must understand the basics of object-oriented programming. Information on object oriented programming and how it is used within plumed can be found here .

Resources

The tarball for this project contains the following directories:

  • rt-coord : a directory containing input files for doing a regtest on an already existing collective variable.
  • rt-second-shell : a directory containing input files for doing a regtest on the collective variable you will implement within this tutorial

At the start of the exercise you should move these two directories to the plumed2/regtest/multicolvar directory of your PLUMED source. You should see many other directories called rt... within the same directory. If you change into any of these directories and issue the following set of commands:

source ../../../sourceme.sh
make

Then you will have run one of the regression tests of PLUMED. If the test runs without a hitch you should get an output something like this:

../../scripts/run
Thu Aug 20 14:33:00 IST 2015
Running regtest in /Users/gareth/Projects/CVception/plumed2/regtest/multicolvar/rt22
cp: ../tmp is a directory (not copied).
++ Test type: driver
++ Arguments: --plumed plumed.dat --trajectory-stride 10 --timestep 0.005 --ixyz trajectory.xyz --dump-forces forces --dump-forces-fmt=%8.4f
++ Processors: 0
/Users/gareth/Projects/CVception/plumed2/regtest/multicolvar/rt22/tmp
Run driver
Done. Here is the error file:

Introduction

PLUMED has two manuals: a manual that is for users of the code and a manual that is for developers of the code.
If you are interested in implementing new features in the code your first point of call should thus be the developer manual, which can be found here . Alternatively, you can get to the front page of the developer manual by clicking the USER/DEVELOPER logo in the top right hand corner of any page of the user manual.

One of PLUMED's nicest features for the developer is that all the code and documentation for any new PLUMED command all appears together in a single file. When you come to implement a new feature it is thus relatively unlikely that you will have to modify any of the files you downloaded. Adding a new feature is simply a matter of adding one further cpp file containing the new method and the documentation for this method. We are able to achieve this by exploiting abstract base classes and polymorphism. All classes that calculate collective variables, print these variables or calculate biases thus inherit from a single base class called Action. You can read about the Action class here . Notice also that this page also shows how all the various classes within the code inherit from this single base class. It is perhaps worth spending a little while browsing through the various branches of this tree and understanding how the classes at each level become increasingly specialised and thus fit for particular purposes.

Lets say you want to implement a new collective variable in PLUMED. One way to start this task would be to write a new class that inherits from the PLMD::Colvar base class.
If you click on the box in the tree for PLMD::Colvar and follow various links on the various subject pages you will eventually get to the following page , which will give you a step-by-step set of instructions for implementing a new collective variable. If you look through the manual you can find similar pages that provide you with instructions for implementing new analysis methods, functions and so on. Our suggestion when you implement something new would thus be to find some similar functionality in the code, look at how it is implemented and to look in the developer manual at the descriptions of the classes that have been inheritted. This process is what we will try and take you through in this short tutorial.

Instructions

Calculating a reasonably complex collective variable

In this first exercise I would like you to look through the manual and work out how to use the functionality that is already available in PLUMED to calculate the following collective variable:

\[ s = \sum_{i=1}^{108} 1 - \frac{1 - \left(\frac{c_i}{4}\right)^6}{1 - \left(\frac{c_i}{4}\right)^{12}} \]

where \(c_i\) is equal to the coordination number of atom \(i\), i.e.:

\[ c_i = \sum_{j \ne i} \frac{1 - \left(\frac{r_{ij}}{1}\right)^6}{1 - \left(\frac{r_{ij}}{1}\right)^{12}} \]

So \(r_{ij}\) is the distance between atom \(i\) and atom \(j\). This collective variable measures the number of coordination numbers that are more than 4 so the summations in the above expressions run over all 108 atoms in this particular system.

Write an input file that computes \(s\) and outputs its value to a file called colvar and that computes both the analytical and numerical derivatives of \(s\) and outputs this information to a file called deriv. You are going to run this calculation in the rt-coord directory that you downloaded with the tarball for this exercise so you should create this input file within that directory. You will need to output the quantities in the colvar and deriv files with only four decimal places.
When you are content with your input run the calculation by typing make. If you have done everything correctly you should see the output that was discussed above.

In setting up your input files you may find it useful to watch our introductory video and this video on some of the features that are available in the code. Obviously, the user manual will be indespensible as well.

Implementing a new collective variable

In this second exercise I would like you to implement the following collective variable:

\[ s = \sum_{i=1}^{108} \int_{57}^{59} \exp\left( -\frac{(x_i - x)^2}{2} \right) \textrm{d}x \]

where \(x_i\) is number of atoms in the second coordination sphere of the \(i\)th atom, i.e.:

\[ s = \sum_{i \ne j} \int_{2}^{4} \exp\left( -\frac{(r_{ij} - r)^2}{2} \right) \textrm{d}r \]

So \(r_{ij}\) is the distance between atom \(i\) and atom \(j\). This collective variable measure the number of atoms that have between 57 and 59 atoms in their second coordination sphere. There are a number of observations we can make here that will help you enormously:

  • Notice that CV is similar to the coordination number CV you calculated in the first example. For both CVs there is a sum over a quantity that is calculated for different sets of atoms. You should thus look at what was done by the routines that calculate the first CV and see what you can reuse.
  • Notice that with the first CV we can calculate the number of coordination numbers that are within a certain range as well as the number of coordination numbers that are less than a certain threshold.
  • You can set the link cell cutoff equal to
std::numeric_limits<double>::max() 

Write an input file that computes \(s\) and outputs its value to a file called colvar and that computes both the analytical and numerical derivatives of \(s\) and outputs this information to a file called deriv. When outputting numbers to colvar and deriv you should output numbers to four and three decimal places repsectively. You are going to run this calculation in the rt-second-shell directory that you downloaded with the tarball for this exercise so you should create this input file within that directory. When you are content with your input run the calculation by typing make. If you have done everything correctly you should see the output that was discussed above.

If you have sufficient time try use doxygen within PLUMED to write the documentation for your new collective variable.

Final thoughts

The aim of this tutorial is not so much to implement the CV. I do not think it is a particularly interesting or useful CV. Instead the hope is that by doing it you will get some idea of how to implement things within PLUMED. Based on my experience there are three key things I wish I could go back and tell my younger self about programming, which I would urge you to learn now:

  • Write less code The more code you write the more bugs you generate. To be totally clear this is not me trying to say I am better at coding than you are - the same statement holds true if I replace each you in the above with an I - it holds true for everyone. In addition, there are lots of smart people out in the world writing code (and again I am not talking about the developers of plumed). Their code is properly tested and faster than anything that you will write so spend your time learning how it works so that you can re-use it.
  • Test your code Notice that I set up directories that you could use to test your code for this tutorial. Testing should always be part of your development workflow and coming up with ways to test your code is hard, which is why we often don't do it enough. Also don't develop stuff in a vacuum get in touch with people who are using the code. You need to test your code on systems that people actually want to simulate and not just on dummy problems. In addition, you should learn to use profiling tools such as valgrind and instruments on the mac so that you can find memory leaks and bottlenecks in your code. When you start doing this properly you will realise that you cannot possibly properly maintain all the code that you have written and you will see clearly that you that you need to write less code.
  • Write documentation for your code Undocumented software is useless. You need to explain how to use your code and to fill your manual with examples of how the code can be used to solve specific and interesting problems. That is to say that you need to provide examples of calculations that users actually want to perform. To be clear here writing a manual that tells users how something like the shake algorithm works in general terms is actually pretty useless. After all a user can go off and find out this information from a textbook, you could thus replace your description with a link to a textbook. What users want from you is an example that is similar to the calculation they actually want to set up. If I were providing documentation for an implementation of shake in an MD code I would thus explain in detail how to set up shake to constrain all the angles and bonds in all the water molecules in my system as it is a fair bet that this is how it will be being used by many users.

I hope you have seen from this tutorial that PLUMED tries to help you with all of these aims. We have a developer manual where we try to explain how to use the code that is already there. In addition, you can quite quickly generate nicely formatted user documentation for new CVs and it is easy to add new regression tests that allow you to test new features. Notice also that whenever commits are made on the origin git repository we use a website called travis-ci to test that the code works across a range of platforms.