Skip to content
Snippets Groups Projects
Commit 7f4eedf5 authored by Gareth Tribello's avatar Gareth Tribello
Browse files

Rewrite of the developers manual.

parent 0bdf242a
No related branches found
No related tags found
No related merge requests found
......@@ -534,7 +534,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = Doc.txt ../src
INPUT = ./Intro.txt ./cvTemplate.txt ./freeTemplate.txt ./funcTemplate.txt ./mdTemplate.txt ./plmdIntro.txt ./usingDoxygen.txt ./parsing.txt ../src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
......
// This document is formatted for Doxygen
/**
\mainpage A Plumed Clone
Plumed 2.0 is written in C++ and uses many of the advanced, object-oriented features of this language. This structure makes the implementation of collective coordinates and free energy methods straightforward. In fact, it should be possible to implement methods and collective coordinates (CV) by creating a single file and without touching any other part of the code. Futhermore, to implement new methodology does not require one to be some sort of C++ wizzard. Rather, the code has been specifically redisigned to make the implementation of new CVs and new free energy methods straightforward so as to encourage people to implement whatever new functionality they require. This document serves then to provide an introduction as to how to go about implementing new functionality in plumed. Within there are templates that give step by step explanation for how to implement new CVs, free energy methods and functions:
- \ref HowToAddACollectiveVariable
- \ref HowToAddAFunction
- \ref HowToAddABias
For more curious contributors we provide a brief introduction to the internal structure of plumed here:
\ref ABriefIntroduction
And finally, for the developers of MD codes, we provide information as to how to incorperate plumed into your codes here:
\ref HowToPlumedYourMD
Lastly, we ask that contributors endeavor to maintain the portability of plumed by, as much as possible, using only the STL library and lapack in modifications. If you need to use any less standard library (e.g. Boost, Sockets) please ensure that your functionality is not installed during a default compilation. However, do feel free to provide alternative compilation options that incorperate your functionality.
Information about C++
http://www.parashift.com/c++-faq-lite/
*/
// This document is formatted for Doxygen
/**
\page HowToAddACollectiveVariable How to add a collective variable
To implement a CV one needs only to create a single cpp file called ColvarNAME.cpp. If one uses the following template for this file then the manual and the calls to the CV will be looked after automatically.
\verbatim
#include "Colvar.h"
#include "ActionRegister.h"
#include <string>
#include <cmath>
#include <cassert>
using namespace std;
namespace PLMD{
//+PLUMEDOC COLVAR NAME
/**
\endverbatim
At this point you provide the description of your CV that will appear in the manual along with an description of the input file syntax and an example. Merging new features of the code into the plumed main branch without proper documentation is punishable by death! Some instructions as to how to format this information is provided here: \ref usingDoxygen
\verbatim
*/
//+ENDPLUMEDOC
/**** We begin by declaring a class for your colvar. This class inherits everything from the Colvar class.
This ensures it has a label, a place to store its value, places to the store the values of the derivatives
and that it can access the various atoms it will employ.
class ColvarNAME : public Colvar {
\endverbatim
Insert declarations for your colvar's parameters here using plumed's \ref parsing.
\verbatim
public:
/**** This is the constructor for your colvar. It is this routine that will do all the reading.
Hence it takes as input a line from the input file.
ColvarNAME(const ActionOptions&);
/**** This is the routine that will be used to calculate the value of the colvar, whenever its calculation is required.
This routine and the constructor above must be present - if either of them are not the code will not compile.
virtual void calculate();
};
/****** The following command inserts your new colvar into plumed by inserting calls to your new
routines into the parts of plumed where they are required. This macro takes two arguments:
The first is the name of your ColvarClass and the second is the keyword for your CV
(the first word in the input line for your CV).
PLUMED_REGISTER_ACTION(ColvarNAME,"KEYWORD")
/**** We now write the actual readin (constructor) and calculations routines for the colvar ****/
ColvarNAME::ColvarNAME(const ActionOptions&ao):
/****** This line sets up various things in the plumed core which colvars rely on.
PLUMED_COLVAR_INIT(ao),
{
vector<int> atoms; /***** You almost always have atoms *****/
\endverbatim
Insert code here to read the arguments of the CV here using plumed's parsing functionality. N.B. The label is read in already elsewhere.
\verbatim
checkRead(); /*** This command checks that everything on the input line has been read properly
/*** The following two lines inform the plumed core that we require space to store the value
of the CV and that the CV will act on a particular list of atoms.
addValueWithDerivatives("");
requestAtoms(atoms);
/ *** For a number of the free energy methods in plumed it is necessary to calculate the
distance between two points in CV space. Obviously, for periodic CVs one must take
periodicities into account when calculating distances and use the minimum image
convention in distance calculations. Hence, we set the periodicity of the cv using
the following two lines.
getValue("")->setPeridodicity(true); // Set this true if the CV is periodic otherwise set if false.
getValue("")->setDomain(min,max); // This routine is only required if the function is periodic. It sets the minimum and maximum values of the colvar.
}
void ColvarNAME::calculate(){
/*** These are the things you must calculate for any cv ***/
double cv_val; /*** The value of the cv ****/
Tensor boxDerivatives; /*** The derivative of the cv with respect to the box vectors ****/
vector<double> derivatives; /**** The derivative of the cv with respect to the atom positions ***/
\endverbatim
Insert the code to calculate your cv, its derivatives and its contribution to the virial here. N.B. Please use, where possible, the plumed's set of CV calculation tools.
\verbatim
/**** Having calculated the cv, its derivative and the contribution to the virial you now
transfer this information to the plumed core using the following three commands. ****/
for(int i=0;i<derivatives.size();i++){ setAtomsDerivatives(i,derivatives[i]); }
setBoxDerivatives(boxDerivatives);
setValue(cv_val);
}
\endverbatim
\section multicvs Mult-component CVs
To avoid code duplication, and in some cases computational expense, plumed has functionality so that a single line in input can calculate be used to calculate multiple components for a CV. For example, PATH computes the distance along the path,\f$s\f$, and the distance from the path, \f$z\f$. Alternatively, a distance can give one the \f$x\f$, \f$y\f$ and \f$z\f$ components of the vector connecting the two atoms. You can make use of this functionality in your own CVs as follows:
- In the constructor we create an additional value for the CV by adding the call PLMD::addValueWithDerivative("new") as well as PLMD::addValueWithDerivatives(””). In addtion set any periodicity for our component using getValue("new")->setPeridicity() and getValue("new")->setDomain(min,max). If this CV is called plum in our input file we can now use both plum and plum.new in any of the functions/methods in plumed.
- Obviously in calculate we now must provide functionality to calculate the values, boxDerivatives and the atom derivatives for both our original plum and its component plum.new. Furthermore, all of this data must be transferred to the plumed core. This is done by the following code:
Here we transfer the value, box derivatives and atomic derivatives for plum.
\verbatim
for(int i=0;i<derivatives.size();i++){ setAtomsDerivatives(i,derivatives[i]); }
setBoxDerivatives(boxDerivatives);
setValue(cv_val);
\endverbatim
Here we transfer the value, box derivatives and atomic derivatives for plum.new.
\verbatim
Value* nvalue=getValue("new");
for(int i=0;i<nderivatives.size();i++){ setAtomsDerivatives(nvalue i,nderivatives[i]); }
setBoxDerivatives(nvalue,nboxDerivatives);
setValue(nvalue,ncv_val);
\endverbatim
Please only use this functionality for CVs that are VERY similar.
*/
// This document is formatted for Doxygen
/**
\page HowToAddABias How to add a biasing potential
*/
// This document is formatted for Doxygen
/**
\page HowToAddAFunction How to add a function
Many collective variables are a function of a number of some set of simpler collective variables. These sorts of collective variables should be implemented should be implemented in plumed as functions so as not to duplicate code.
Much like a CVs one can implement a function by creating a single cpp file called FunctionNAME.cpp. If one uses the following template for this file then the manual and the calls to the CV will be looked after automatically.
\verbatim
#include "ActionRegister.h"
#include "Function.h"
#include <cmath>
#include <cassert>
using namespace std;
namespace PLMD{
//+PLUMEDOC FUNCTION COMBINE
/**
\endverbatim
At this point you provide the description of your function that will appear in the manual along with a description of the input file syntax and an example. Merging new features of the code into the plumed main branch without proper documentation is punishable by death! Some instructions as to how to format this information is provided here: \ref usingDoxygen
\verbatim
*/
//+ENDPLUMEDOC
/**** We begin by declaring a class for your function. This class inherits everything from the function class.
This ensures it has a label, a place to store its value, places to the store the values of the derivatives
and that it knows which of the colvar objects its value depends on.
class FunctionNAME :
public Function
{
\endverbatim
Insert declarations for your function's parameters here.
\verbatim
/**** This is the constructor for your function. It is this routine that will do all the reading.
Hence it takes as input a line from the input file.
FunctionCombine(const ActionOptions&);
/**** This is the routine that will be used to calculate the value of the function, whenever its calculation is required.
This routine and the constructor above must be present - if either of them are not the code will not compile.
void calculate();
};
/****** The following command inserts your new function into plumed by inserting calls to your new
routines into the parts of plumed where they are required. This macro takes two arguments:
The first is the name of your FunctionClass and the second is the keyword for your function
(the first word in the input line for your function).
PLUMED_REGISTER_ACTION(FunctionNAME,"COMBINE")
FunctionNAME::FunctionNAME(const ActionOptions&ao):
/*** These two lines set up various things in the plumed core whcih functions rely on.
Action(ao),
Function(ao)
{
\endverbatim
Insert code here to read the arguments of the function here using plumed's \ref parsing. N.B. The label and arguments (i.e. the cvs on which the function depends are read in already elsewhere.
\verbatim
/ *** For a number of the free energy methods in plumed it is necessary to calculate the
distance between two points in CV space. Obviously, for periodic CVs one must take
periodicities into account when calculating distances and use the minimum image
convention in distance calculations. Functions too are used as cvs in these methods
and thus it is necessary to provide periodicities for these objects too. In theory it
should be possible to determine the periodicity of a function from the periodicity of the
underlying CVs. However, in practise this is very difficult to do. We therefore recommend
that you include the following few lines of code so that the periodicity of functions can
be specified by the user in input.
vector<string> period;
double min(0),max(0);
parseVector("PERIODIC",period);
if(period.size()==0){
}else if(period.size()==1 && period[0]=="NO"){
getValue("")->setPeriodicity(false);
} else if(period.size()==2 && Tools::convert(period[0],min) && Tools::convert(period[1],max)){
getValue("")->setPeriodicity(true);
getValue("")->setDomain(min,max);
}
checkRead(); /*** This command checks that everything on the input line has been read properly
/*** The following line informs the plumed core that we require space to store the
value of the function and the derivatives. ***/
addValueWithDerivatives("");
}
\verbatim
void FunctionCombine::calculate(){
/*** These are the things you must calculate for any function ***/
double cv_val; /*** The value of the function ****/
vector<double> derivatives; /**** The derivative of the function with respect to the cvs ***/
\endverbatim
Insert code here to calculate your function and its derivatives with repsect to the underlying cvs here. If possible please try to avoid duplicating functionality that is already available elsewhere in the code.
\verbatim
/**** Having calculated the function and its derivatives you now transfer this information
to the plumed core using the following two commands. ****/
for(int i=0;i<derivatives.size();i++){ setAtomsDerivatives(i,derivatives[i]); }
setValue(cv_val);
}
}
\endverbatim
\section multicvsf Multi-component functions
To avoid code duplication, and in some cases computational expense, plumed has functionality so that a single line in input can calculate be used to calculate multiple components for a function. You can make use of this functionality in your own CVs as follows:
- In the constructor we create an additional value for the function by adding the call PLMD::addValueWithDerivative("new") as well as PLMD::addValueWithDerivatives(””). Please note you must provide keywords in input to provide periodicity information for both your function and all of its components. The periodicities of the components should then be set using getValue("new")->setPeridicity() and getValue("new")->setDomain(min,max). If we call this function flum in our input file we can now use both flum and flum.new in any of the functions/methods in plumed.
- Obviously in calculate we now must provide functionality to calculate the values and derivatives for both flum and its component flum.new. Furthermore, all of this data must be transferred to the plumed core. This is done by the following code:
Here we transfer the value and derivatives for flum.
\verbatim
for(int i=0;i<derivatives.size();i++){ setDerivatives(i,derivatives[i]); }
setValue(cv_val);
\endverbatim
Here we transfer the value and derivatives for plum.new.
\verbatim
Value* nvalue=getValue("new");
for(int i=0;i<nderivatives.size();i++){ setDerivatives(nvalue i,nderivatives[i]); }
setValue(nvalue,ncv_val);
\endverbatim
Please only use this functionality for functions that are VERY similar.
*/
// This document is formatted for Doxygen
/**
\page HowToPlumedYourMD How to add plumed to an MD code
Plumed ships with scripts that can be used to add it to many of the standard MD packages. Obviously though, if no patch is provided for the MD code you use then you will have to write one yourself. Plumed has been designed so that it can be added to an MD code either statically or as a dynamic library. It is NOT possible to compile plumed as a static library and link the library. Furthermore, unlike the previous version of plumed, the plumed source code is not compiled at the same time as your MD code is compiled. Instead plumed now has its own makefile and is compiled separately to the MD engines that rely on it. This makes plumed patches considerably simpler as now they only do two things:
- Modify the makefile so that the plumed is linked to the MD code
- Modify the source code to add all the required calls to plumed
\section makefile Modifying your makefile
Once the plumed source code has been compiled a file called src/Plumed.inc will be created. This file must be included in your MD code's makefile as it informs the code where to find all the plumed source. In particular, within the code the three variables described below are defined one of which must be added to the command that does the linking for your MD engine:
- \$(PLUMED_OBJ) - This will statically link plumed to your MD engine
- \$(PLUMD_SHARED_OBJ) - This will dynamically bind plumed to your MD engine. Furthermore, plumed will not run if you move the libplumedKernel.so library to a new location after compilation.
- \$(PLUMED_KERNEL) - This allows you to specify the location of plumed at runtime through the PLUMD_KERNEL environment variable. Obviously, if at runtime this variable is not set, then none of plumed functionality will be available.
For consistency with the other plumed patches please ensure that your new patch allows users to compile with all three options. Other users should be able to select which compilation mode they require using the following flags:
- --static for \$(PLUMED_OBJ)
- --shared for \$(PLUMED_SHARED_OBJ)
- --runtime for \$(PLUMED_WRAPPER)
\section language Language dependence
The interface between plumed and the MD codes is written is plain C so it is compatible with codes that are written in plain C, C++ and fortran. This interface contains four routines:
- plumed_installed - This routine ensures that a version of plumed is available
- plumed_create - This routine creates the plumed object
- plumed_command - This routine passes some infomration to plumed or instructs plumed to perform some action
- plumed_finalize - This routine destroys the plumed objects
The first of these takes in an int*, which is set equal to 1 if a version of plumed is found. The remaining three routines can be called in one of three ways. In C++ codes you can either declare a PLMD::Plumed object from plumed or inherit the PLMD::Plumed class. You can then call the methods of this class to do the above. In this case the creation and desctruction of the plumed object is looked after and one need only use the cmd method (which is essentially a wrapper to plumed_cmd) to pass various pieces of data between you md code and plumed as described below. For C and C++ codes one can also store the plumed object dynamically in which case these routines are called as:
- plumed_create() - which will return a pointer to plumed object that must be saved.
- plumed_cmd(plumed, const char*, const void* ) - here the first argument must be the pointer returned by plumed_create while the second and third describe are used to pass a pointer to some data in the code along with guidance as to what the data is.
- plumed_finalize(plumed) - here the argument is the pointer return by plumed_create.
while for fortran codes you must store the plumed pointer as a global object and use the global interface by calling:
- plumed_g_create()
- plumed_g_command(const char* ,const void* ) - Clearly the two arguments here are the second two arguments in plumed_cmd
- plumed_g_finalize()
\section mdImplementation A practical example
We now describe how to pass data to plumed in from an MD code that is written in C/C++. If your code is written in fortran follow the same procedure but use the global routines as described in the previous section. In files containing calls to plumed you will have to include the Plumed.h file. In addition, you will also have to define a plumed obect that is visible in all these routines and you will probably like to define some sort of plumedswitch, which can be read in from the input to your code and used to tell the code whether or not this is to be a run with plumed. Finally, you might like to include something in input so that you specify the name of the plumed input file. How these things are best done will depend on your code and so we leave it to your discretion.
Plumed must perform three actions inside your MD code:
- It must be initialized before the main MD loop starts so that the plumed input files are read in.
- It must be called every MD step so that the forces from the bias can be computed.
- It must be finalized when the simulation is completed
The various calls that can be used during initialization are as follows:
\verbatim
plumed plumedmain; plumedmain=plumed_create(); // Create the plumed object
// Calls to pass data to plumed
plumed_cmd(plumedmain,"setRealPrecision",&real_precision); // Pass a pointer to the precision used in the code to plumed
plumed_cmd(plumedmain,"setKBoltzman",&kB); // Pass a pointer to the value of boltzmanns constant in this code (why?)
plumed_cmd(plumedmain,"setMDEnergyUnits",&energyUnits); // Pass a pointer to the conversion factor between the energy unit used in your code and kJ mol-1
plumed_cmd(plumedmain,"setMDLengthUnits",&lengthUnits); // Pass a pointer to the conversion factor between the length unit used in your code and nm
plumed_cmd(plumedmain,"setMDTimeUnits",&timeUnits); // Pass a pointer to the conversion factor between the time unit used in your code and fs?
plumed_cmd(plumedmain,"setPlumedDat",&plumedInput); // Pass the name of the plumed input file from the md code to plumed
plumed_cmd(plumedmain,"setMPIComm",&MPI_COMM_WORLD); // Pass a pointer to the MPI communicator to plumed?
plumed_cmd(plumedmain,"setNatoms",&natoms); // Pass a pointer to the number of atoms in the system to plumed
plumed_cmd(plumedmain,"setMDEngine","gromacs"); // Pass the name of your md engine to plumed
plumed_cmd(plumedmain,"setLog",fplog); // Pass the file on which to write out the plumed log
plumed_cmd(plumedmain,"setLogFile",fplog);
plumed_cmd(plumedmain,"setTimestep",&delta_t); // Pass a pointer to the molecular dynamics timestep to plumed
// Calls to do the actual initialization (all the above commands must appear before this call)
plumed_cmd(plumedmain,"init",NULL); // Do all the initialization of plumed
plumed_cmd(plumedmain,"read",read); // Read the plumed input. N.B. This is called during init and so this call is only required in special cases.
\endverbatim
Please note that if your code is in fortran the mpi communicator should be passed using:
\verbatim
call plumed_g_cmd("setMPIFComm"//char(0),MPI_COMM_WORLD)
\endverbatim
The various calls that can be used pass data and calculate the forces due to the bias are as follows:
\verbatim
// Calls to pass data to plumed
plumed_cmd(plumedmain,"setStep",&step); // Pass a pointer to the current timestep to plumed
/ *** The way that you pass positions will depend on how they are stored in your code. If the x, y and z position are all stored in a single array you may use:
plumed_cmd(plumedmain,"setPositions",&pos[0][0]); // Pass a pointer to the first element in the atomic positions array to plumed
/ *** Othersize if you pass the three separate vectors of x, y and z positions using:
plumed_cmd(plumedmain,"setPositionX",&x[0]); // Pass a pointer to the first element in the array of x component of the atomic positions to plumed
plumed_cmd(plumedmain,"setPositionY",&y[0]); // Pass a pointer to the first element in the array of y component of the atomic positions to plumed
plumed_cmd(plumedmain,"setPositionZ",&z[0]); // Pass a pointer to the first element in the array of z component of the atomic positions to plumed
plumed_cmd(plumedmain,"setMasses",&mass[0]); // Pass a pointer to the first element in the masses array to plumed
plumed_cmd(plumedmain,"setCharges",&charge[0]); // Pass a pointer to the first element in the charges array to plumed
plumed_cmd(plumedmain,"setBox",&box[0][0]); // Pass a pointer to the first element in the box share array to plumed
plumed_cmd(plumedmain,"setEnergy",&poteng); // Pass a pointer to the current value of the potential energy to plumed?
/ *** The way that you pass forces will depend on how they are stored in your code. If the x, y and z force are all stored in a single array you may use:
plumed_cmd(plumedmain,"setForces",&f[0][0]); // Pass a pointer to the first element in the foces array to plumed
/ *** Othersize if you pass the three separate vectors of x, y and z forces using:
plumed_cmd(plumedmain,"setForcesX",&fx[0]); // Pass a pointer to the first element in the array of the x components of the atomic forces to plumed
plumed_cmd(plumedmain,"setForcesY",&fy[0]); // Pass a pointer to the first element in the array of the y components of the atomic forces to plumed
plumed_cmd(plumedmain,"setForcesZ",&fz[0]); // Pass a pointer to the first element in the array of the z components of the atomic forces to plumed
plumed_cmd(plumedmain,"setVirial",&force_vir[0][0]); // Pass a pointer to the first element in the virial array to plumed
// Calls to do actual calculations
plumed_cmd(plumedmain,"calc",NULL); // Calculate and apply forces from the biases defined in the plumed input
// In some cases it can be faster to break up the above command into its individual setps:
plumed_cmd(plumedmain,"prepareCalc",NULL); // Prepare to do a calculation by requesting all the atomic positions from the MD code
plumed_cmd(plumedmain,"prepareDependencies",NULL); // Work out what we are calculating during this MD step (this is the first step of prepareCalc)
plumed_cmd(plumedmain,"shareData",NULL); // Request all the atomic positions from the MD code (this is the second step of prepareCalc)
plumed_cmd(plumedmain,"performCalc",NULL); // Use the atomic positions collected during prepareCalc phase to calculate colvars and biases.
// Some extra calls that might come in handy
plumed_cmd(plumedmain,"createFullList",&n); // Create a list containing of all the atoms plumed is using to do calculations (return the number of atoms in n)
plumed_cmd(plumedmain,"getFullList",&list); // Return a list (in list) containing all the indices plumed is using to do calculations
plumed_cmd(plumedmain,"clearFullList",NULL); // Clear the list of all the atoms that plumed is using to do calculations
plumed_cmd(plumedmain,"clear",clear); // Clear and delete all the pointers inside plumed.
\endverbatim
The plumed calls for the finalization tasks is as follows:
\verbatim
plumed_finalize(plumedmain); // Call the plumed destructor
\endverbatim
\section mpicodes Dealing with parallelism
Plumed has functionality to deal with parallel MD codes. The particular form of the functionality used to do this (and the frequency with which you will have to call these routines) will depend on whether your code is parallelism using a domain decomposition or particle decomposition strategy. The calls for required for using this functionality are as follows:
\verbatim
plumed_cmd(plumedmain,"setAtomsNlocal",&nlocal); // Pass a pointer to the number of atoms on this node
plumed_cmd(plumedmain,"setAtomsGatindex",gatindex); // Pass an array containing the indices of all the atoms on this node (used for domain decomposition)
plumed_cmd(plumedmain,"setAtomsContiguous",&start); // Number the atoms on this node from start to start+nlocal (used for particle decomposition)
plumed_cmd(plumedmain,"getApiVersion",api); // Pass the api version that plumed is using (what does this mean)???
\endverbatim
\section Notes Notes
Compiler options to use shared libraries on many architectures:
http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
*/
// This document is formatted for Doxygen
/**
\page parsing parsing functionality
By now you are probably familiar with the way that plumed2 input looks:
\verbatim
DISTANCE ATOMS=0,300 LABEL=dist NOPBC
RESTRAINT ARG=dist KAPPA=1.0 AT=1.0
\endverbatim
Within the code this information will be read by either parseVector or parseFlag. parseFlag is called using:
\verbatim
parseFlag("NOPBC",nopbc)
\endverbatim
This will then read the list of action objects you passed to the constructor and look for the keyword NOPBC. If the keyword is found then it is deleted from the list of action objects, while the boolian nopbc is returned as true otherwise the boolian is returned as false. parseVector is called using:
\verbatim
std::vector<double> vec;
parseVector("KAPPA",vec);
\endverbatim
This routine will then read the list of action objects you passed to the constructor and look for the keyword KAPPA. This keyword will be followed by an equals sign and a list of comma separated numbers. These numbers are read into the vector vec and passed back to the main code. (N.B. The size of the vector is worked out automitically by parseVector from the input. In addition the vector can be a vector of int or a vector of real.) Much like parseFlag, parseVector will delete the keyword and the list from the list of actionObjects once it has completed. When you have finished reading all your arguments you should call checkRead() - this routine checks that everything in the list of ActionOptions taken from the input has been read in.
Please note when you are implementing functionality to read the plumed input that you never need to implement anything to read ARGS and LABEL as these keywords are read elsewhere in the code.
*/
// This document is formatted for Doxygen
/**
\page ABriefIntroduction A brief introduction to the plumed core
\section intro Introduction
Every line in a plumed input file, regardless of whether it specifies that one is to calculate a colvar, a function of colvars or a bias, instructs plumed to create a PLMD::Actionobject. Any call to plumed tells it perform all the actions defined in the plumed input file one after the other. For programmers (like this author) unfamiliar with some of the more advanced features of C++ this may seem somewhat bizzare. After all calculating a metadynamics bias is very different to calculating a collective coordinate. This is possible however because plumed classes inherit variables and methods from each other. This means that we can write a PLMD::Bias, PLMD::Colvar or PLMD::Function class in which we can call all the methods and variables in PLMD::Action as if they were inside the PLMD::Bias, PLMD::Colvar or PLMD::Function. Consequently, we can avoid duplication by placing all the functionality that is common to calculating biases and colvars in a single object (PLMD::Action), which we can inherit into the PLMD::Bias and PLMD::Colvar classes that contain all the functionality that is not common to the two things. Furthermore, we can include virtual methods in the PLMD::Action class that we know our PLMD::Bias and PLMD::Colvar objects will perform but that we know will be performed differently by the two classes (for example we know that both will probably calculate something but that each will do this differently). These two facts make it straightforward to write a plumed core, which just performs a series of actions, that can be modified and added to by other contributors later.
\section free-energy Free energy methods in plumed
Many of the free energy methods that are implemented in plumed are reliant on the definition of some collective coordinates. A bias potential is then added on these collective coordinates, which then introduces new forces on to the underlying atoms. Oftentimes however, one may not want to bias the collective coordinates directly. Instead one might be interested in biasing a function of the collective coordinates, which adds a further layer of complexity. Therefore the mode of action for a free energy method is, in the most general case, as follows:
- Get the atomic positions, \f$x\f$.
- Compute the collective coordinates from the positions, \f$s(x)\f$.
- Compute functions \f$f[s(x)]\f$ of the collective coordinates from \f$s(x)\f$.
- Compute the bias \f$B| f[s(x)] |\f$, which is a function of \f$f[s(x)]\f$ and the derivative of the bias with respect to \f$f[s(x)]\f$, \f$\frac{\textrm{d}B}{\textrm{d}f}\f$.
- Compute the derivative of the bias with respect to the collective coordinates, \f$\frac{\textrm{d}B}{\textrm{d}s} = \frac{\textrm{d}B}{\textrm{d}f} \frac{\textrm{d}f}{\textrm{d}s}\f$
- Compute the derivative of the bias with respect to the atomic positions, \f$\frac{\textrm{d}b}{\textrm{d}x} = \frac{\textrm{d}B}{\textrm{d}f} \frac{\textrm{d}f}{\textrm{d}s} \frac{\textrm{d}s}{\textrm{d}x} \f$
- Apply the resulting forces to the atoms of the system.
From this mode of action we might therefore imagine that data flows through plumed as described below:
- From the MD code pass the atom positions, \f$x\f$ to PLMD::Colvar, calculate colvars, \f$s(x)\f$ and derivatives \f$\frac{\textrm{d}s}{\textrm{d}x}\f$.
- Pass \f$s(x)\f$ from PLMD::Colvar to PLMD::Function, calculate functions \f$f[s(x)]\f$ and derivatives \f$\frac{\textrm{d}f}{\textrm{d}s}\f$.
- Pass \f$f[s(x)]\f$ from PLMD::Function to PLMD::Bias, calclate the bias \f$B| f[(x)] |\f$ and derivatives \f$\frac{\textrm{d}B}{\textrm{d}f}\f$.
- Pass the derivative \f$\frac{\textrm{d}B}{\textrm{d}f}\f$ of the bias from PLMD::Bias to PLMD::Function and compute the derivative of the bias with repect to the cvs \f$\frac{\textrm{d}B}{\textrm{d}f} \frac{\textrm{d}f}{\textrm{d}s}\f$.
- Pass the derivative \f$\frac{\textrm{d}B}{\textrm{d}f} \frac{\textrm{d}f}{\textrm{d}s}\f$ from PLMD::Function to PLMD::Colvar and compute the derivative of the bias with respect to the atomic coordinates \f$\frac{\textrm{d}B}{\textrm{d}f}\frac{\textrm{d}f}{\textrm{d}s}\frac{\textrm{d}s}{\textrm{d}x}\f$.
- Pass the derivatives \f$\frac{\textrm{d}B}{\textrm{d}f}\frac{\textrm{d}f}{\textrm{d}s}\frac{\textrm{d}s}{\textrm{d}x}\f$ to the MD code and apply the forces.
This is roughly the way that plumed 1.0 operated. Plumed 2.0 operates differently so that new CVs and free energy methods can be implemented more straightforwardly. The work flow for plumed 2.0 is therefore:
- Iterate over the list of PLMD::Action objects, establish whether any contain PLMD::ActionPilot objects.
- For the PLMD::ActionPilot objects check if we are supposed to perform an action at this particular MD step. If it is activate the action.
- When any object is activated we must check whether or not it contains a PLMD::ActionWithArguments object. These objects tell plumed that before performing a particular action we must perform some other action (for example before computing the bias in metadynamics we must compute the collective variables). If we find such arguments we activate all arguments listed in the PLMD::ActionWithArguments object belonging to this particular PLMD::Action (i.e. when peforming metadynamics one must make sure that all the collective coordinates on which the bias depends are calculated first).
- Iterate over the list of all the active PLMD::Action objects calculating all values and derivatives and store them inside PLMD::ActionWithValue objects (N.B. a PLMD::ActionWithValue holds a vector of PLMD::Value objects).
- As already mentioned the dependencies of PLMD::Function and PLMD::Bias objects on the PLMD::Colvar objects is stored within a PLMD::ActionWithArguments object. The reason for this apprantly-arbitrary, additional layer of complexity being that PLMD::Bias objects can depend on both PLMD::Function objects and PLMD::Colvar objects. PLMD::ActionWithArguments is a list of PLMD::Values. It is used to tell a PLMD::Action that it must wait for data to be loaded in the set of listed PLMD::Value (by other PLMD::Actions) prior to calculating the particlar PLMD::Action. In practise this means that the order for the directives in the input matters in plumed 2 as the various PLMD::Actions are always passed through in the order they are read in from input.
- By this stage we have computed \f$s(x)\f$, \f$f[s(x)]\f$, \f$B| f[s(x)] |\f$, \f$\frac{\textrm{d}B}{\textrm{d}f}\f$, \f$\frac{\textrm{d}f}{\textrm{d}s}\f$ and \f$\frac{\textrm{d}s}{\textrm{d}x}\f$. This data has all been stored inside PLMD::Value objects. In other words, unlike in the previously described workflows, the data is stored in a manner that does not descriminate between the results from calculations in PLMD::Colvar, PLMD::Function and PLMD::Bias. Instead, all the data is stored in equivalent PLMD::Value objects. Plumed understands that one cannot compute \f$f[s(x)]\f$ or \f$B| f[s(x)] |\f$ without first computing \f$s(x)\f$ and \f$f[s(x)]\f$ as this information is stored inside the PLMD::ActionWithArguments objects.
- Next we apply the chain rule to calculate the derivative of the bias with respect to the atomic positions in three steps.
- In the first step we loop over all the PLMD::Bias objects and pass \f$-\frac{\textrm{d}B}{\textrm{d}v}\f$ to the PLMD::Value objects listed in the PLMD::ActionWithArguments object.
- In the second step we loop over all the PLMD::Function objects. If there is a bias on any of these objects we will have passed information on \f$-\frac{\textrm{d}B}{\textrm{d}f}\f$ to the relevant PLMD::Value objects in this classes PLMD::ActionWithValue class. Hence, we can calculate \f$-\frac{\textrm{d}B}{\textrm{d}s} = -\frac{\textrm{d}B}{\textrm{d}f}\frac{\textrm{d}f}{\textrm{d}s}\f$ and pass this information to the PLMD::Value objects listed in PLMD::ActionWithArguments.
- In the final step we calculate the forces on the atoms by looping over all PLMD::Colvar objects. Once again if there is a bias (or a bias on a function of one of these values) \f$-\frac{\textrm{d}B}{\textrm{d}s}\f$ will have been passed to the relevant PLMD::Value class so that we can calculate \f$-\frac{\textrm{d}B}{\textrm{d}x} = -\frac{\textrm{d}B}{\textrm{d}f}\frac{\textrm{d}f}{\textrm{d}s}\frac{\textrm{d}s}{\textrm{d}s}\f$. We now apply these forces to the atoms using the PLMD::ActionAtomistic class.
The above list describes the function of the majority of the classes in the plumed core. In practise to add to plumed you do not need to understand the details of how each of these classes functions as you shouldn't need to touch them. It is perhaps useful to understand what each one is doing however so that you can better understand the code structure.
\section parallel Multiple Replicas
Many free energy methods are reliant on running a number of parallel MD simulations. From the point of view of implementation these algorithms can be broadly categorised thus:
- Embarrasingly parallel algorithms such as umbrella sampling that require no communication between simulations.
- Simulations with time dependent biases, which are sped up by collecting the time dependent bias on a number of nodes simultaneously. An example of this sort is multiple walkers metadynamics.
- Replica exchange simulations in which different parameters are used for simulations on different nodes and periodic attempts are made to exchange parameters between configurations on different nodes.
The first of these types of simulations is trivial to implement in plumed as all the "communication" between nodes is done in post processing and thus nothing needs to be added to plumed. Similarly the second relies little work in the plumed core as generally the objects being communicated are highly method development. For developers implementing these sorts of methods we recommend looking into the implemation of multiple walkers metadynamics. In this method the hills are passed between nodes and in plumed this is done by writing and reading files.
The third method in the above list is the most involved in terms of implementation. The first complication for implementing these sorts of methods in plumed is that different algorithms implement them differently. For instance, during a swapping event gromacs exchanges the configuration information on the two nodes. This makes the bussiness of the plumed core trivial as in the next call to plumed the swap of configurations will mean that a different configuration will be received. Hence, one needs only to sort the accept/reject move in the method of interest. That is to say gromacs looks after all the communication between replicas.
Many other codes implement replica exchange by exchanging the parameters between nodes while keeping the configurations on a the nodes fixed. From the point of view of plumed this means that we must exchange the bias between the different nodes during an exchange step. In other words we must swap the list PLMD::Actions between the two nodes taking care to preserve the history dependent part on the new node. The functionality to do this passing is inside PLMD::SomeClassOrOther and is done by passing information in files. From the point of view of someone implementing some new biassing functionality this means that one is forced by the inheritence to write a routine called ??? that tells plumed how to pass any time dependent parts of the bias between nodes.
\section restart Restarting
Plumed 2.0, unlike plumed 1.0, contains functionality to perform a restart of a previous simulation. If we are allowed to be philosophical for a moment we can think of a restart as simply an exchange of information between two nodes in which there is a long time delay between the sending of the data and the receiving of it. Hence, to prevent code from being replicated and because all the replica exchange bussiness is done through files, all the checkpointing in plumed is done using the functionality described in the previous section.
\section Notes Notes
Information about C++
http://www.parashift.com/c++-faq-lite/
*/
// This document is formatted for Doxygen
/**
\page usingDoxygen Using doxygen to create plumed documentation
Plumed's documentation is created automatically from comments in the source code using the following packages:
- Doxygen: http://www.doxygen.org
- Graphviz: http://www.graphviz.org/
To create documentation you need only type it in the top part of your cpp source code files.
\section sampleInput Creating sample input
You can create sample input by typing:
\verbatim
\verbatim
EXAMPLE - AN EXAMPLE INPUT LINE
\ endverbatim /*** But with no space between the \ and the endverbatim
\endverbatim
which will put the following into the manual:
\verbatim
EXAMPLE - AN EXAMPLE INPUT LINE
\endverbatim
\section formula Creating latex formulae
You can add formulae in latex using:
\verbatim
This is an inline equation \f$s=y+x\f$ but this is an equation:
\f[
r = \sqrt{ \mathbf{s}^T \mathbf{C}^{-1} \mathbf{s} }
\f]
And this is an equation array:
\f{eqnarray*}{
f &=& \frac{1}{2} \\
g &=& \frac{2}{3}
\f}
\endverbatim
In the manual this will be translated into:
This is an inline equation \f$s=y+x\f$ but this is an equation:
\f[
r = \sqrt{ \mathbf{s}^T \mathbf{C}^{-1} \mathbf{s} }
\f]
And this is an equation array:
\f{eqnarray*}{
f &=& \frac{1}{2} \\
g &=& \frac{2}{3}
\f}
\section lists Creating lists
You can create lists of data using:
\verbatim
- First item in list
- Second item in list
\endverbatim
which becomes:
- First item in list
- Second item in list
\section formatting Formatting your documentation
You can create a new section in your documentation using:
\verbatim
\section formula Creating latex formulae
\endverbatim
In fact I used this very command earlier in writing this page. I can therefore reference it here (\ref formula) by using:
\verbatim
\ref formula
\endverbatim
I can also reference external webpages by typing web addresses directly in my documentation.
*/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment