diff --git a/developer-doc/AddingAMeasure.txt b/developer-doc/AddingAMeasure.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd83ad0ba950a7c26af83e13667680b583aa0947 --- /dev/null +++ b/developer-doc/AddingAMeasure.txt @@ -0,0 +1,117 @@ +// This document is formatted for Doxygen +/** + +\page AddingAMetric Implementing methods for calculating the distances between pairs of configurations + +The PLMD::reference module is used in many parts of PLUMED (e.g. path collective variables, field-cvs and analysis methods). +The classes in this module allow one to calculate the distance between pairs of trajectory frames. The reason that this is +a module rather than a single method is that there are a wide variety of different ways of calculating the distance between +two frames. One could, for example, calculate the RMSD distance between the two frames. Alternatively, one can calculate +a large number of collective variables and compare the values these variables have in the two configurations. Lastly, one +could somehow combine some element of RMSD calculation with the calculation of some set of collective variables. As with +so many things the way in which one wishes to calculate the distance between two configurations will depend on the problem +one is endeavoring to solve. The aim of the PLMD::reference module is thus to provide the user unlimited flexibility in the +way that the matrix of distances can be calculated in analysis methods such as sketch-map or in biasing methods such as path +cvs. I say unlimited because, although the particular distance measure the user needs many not currently be implemented in +PLUMED, he/she always has the option to implement this new distance metric in the reference module and then access it in the +full range of analysis and biasing tools that are already available in the code. The following provides instructions for +implementing a new way of calculating the distance between a pair of trajectory frames in the code using the PLMD::reference +module. As always once your new method is implemented you can access it in all the places where pairwise distances are employed +because of the way that PLUMED exploits inheritance and polymorphism. + +\section adding Creating your measure + +To create a new way of measuring the distances between pairs of atoms you must write a new class in the reference directory. +An example declaration for such a class is given below: + +\verbatim +class OptimalRMSD : public RMSDBase { +private: + bool fast; + RMSD myrmsd; +public: + OptimalRMSD(const ReferenceConfigurationOptions& ro); + void read( const PDB& ); + double calc( const std::vector<Vector>& pos, const bool& squared ); +}; +\endverbatim + +In this case we are inheriting from PLMD::RMSDBase but the particular class you will want to inherit from will depend on the +manner in which the distance is calculated. To then ensure that your new measure can be used throughout the code you need +to include the MetricRegister.h file and the following line: + +\verbatim +PLUMED_REGISTER_METRIC(OptimalRMSD,"OPTIMAL") +\endverbatim + +Once again dynamic polymorphism is exploited agin here. With this example the command above ensures that PLMD::OptimalRMSD objects +are used whenever the command METRIC=OPTIMAL is found in the PLUMED input. + +Your new class must contain a constructor, a method to read in the configuration from a pdb file (read) and a method to calculate +the distance between the reference configuration and the input position (calc). Please be aware that the number of arguments +to this method will change depending on which base class you inherit from in creating your new measure object. + +The inheritance structure of these routines is rather complicated looking. In essence, however, the base class underlying all +these classes in PLMD::ReferenceConfiguration. There are then two classes PLMD::ReferenceArguments and PLMD::ReferenceAtoms that +can be multiply inherited in any derived classes. PLMD::ReferenceArguments provides tools for dealing with distance measures that +involve colvars. PLMD::ReferenceAtoms provides tools for dealing with distance measures that involve the positions of atoms. +Base classes such as PLMD::SingleDomainRMSD and PLMD::RMSDBase are there essentially so that we can use particular sets of metrics +in secondary structure variables and the RMSD class respectively. Essentially within these two objects the RMSD is calculated by +calling the calc member of the abstract base class PLMD::SingleDomainRMSD and PLMD::RMSDBase. This allows one to use the +appropriate set of measures within these particular functions. + +\section args Dealing with colvars + +There are essentially three ways in which you might wish to calculate the distance between two sets of reference colvar values: + +- You will calculate the euclidean distance using pythagoras theorem +- You calculate the normalised euclidean distance in which pythagoras theorem is again used but each pair of components is given a separate weight +- You calculate the Mahalonobis distance in which the distance is calculated as \f$x^T M x\f$ where $\fx\$ is the displacement vector and $\fM\f$ is a matrix. + +These three methods are all implemented within PLUMED and are in the classes PLMD::EuclideanDistance, PLMD::NormalizedEuclideanDistance and PLMD::MahalanobisDistance +respectively. If you look in these three classes you will note that there is a very small amount of code in each of them. Essentially the calculation of the +distance and the reading in of the PDB file are looked after by the methods PLMD::ReferenceArguments::calculateArgumentDistance and +PLMD::ReferenceArguments::readArgumentsFromPDB respectively. To reuse these functionalities you need to add the command: + +- hasmetric=true in the constructor if you want to use the Mahalonobis distance in your new metric +- hasweights=true in the constructor if you want to use the normalised euclidean distance in your new metric + +If you want to use the euclidean distance you can use PLMD::ReferenceArguments::calculateArgumentDistance and PLMD::ReferenceArguments::readArgumentsFromPDB +without any further instructions. Notice these methods will still work if you use a combination of atom positions and colvars in your measure. They will +give the part of the measure due to the arguments - you will be required to do some further calculation to get the bit involving the atoms. + +\section atoms Dealing with atoms + +All the distance measures that we work with involve the positions of the atoms in the two configurations. If we work with colvars we +just do the calculation of the distance from the positions of the atoms in an indirect way - we calculate some intermediary quantities +from the positions of the atoms and then calculate the set of difference between these intermediary quantities. There are cases, +however, such as when we are working with RMSD distances where it is useful to calculate the distance directly from the set of atomic +positions. That is to say there are cases where these intermediary quantities are not useful. If you are implementing such a measure +you will need to write a class that inherits from PLMD::ReferenceAtoms either directly or indirectly. + +Within the read method you can read the atoms in the PDB file by using the method PLMD::ReferenceAtoms::readAtomsFromPDB. Within calc you can then +access the positions of these read in atoms by using the method PLMD::ReferenceAtoms::getReferencePositions() or by using PLMD::ReferenceAtoms::getReferencePosition. +It is useful to think carefully about how you can reuse other parts of the code when implementing new reference methods. As an example notice +how PLMD::OptimalRMSD and PLMD::SimpleRMSD make extensive use of the PLMD::RMSD class. Similarly notice how the PLMD::OptimalRMSD, +PLMD::SimpleRMSD and PLMD::DRMSD classes are reused in PLMD::MultiDomainRMSD. + +\section docs Adding documentation for your measure + +To test whether you have implemented you new measure correctly you should implement a small Action that calculates the +distance between the instantaneous positions of the atoms and some read in reference configuration. The methods +PLMD::colvar::RMSD, PLMD::colvar::DRMSD, PLMD::colvar::MultiRMSD and PLMD::function::Target perform these functions for +the set of measures that are currently implemented within the reference module. You will need to do something similar +in your test action. + +You will notice that the documentation in these files starts with the line: + +\verbatim +//+PLUMEDOC DCOLVAR TARGET +\endverbatim + +The DCOLVAR tag is important here as including this tag ensures that the documentation for these objects appears in the +appropriate part of the manual. This page of the manual is linked to from all of the pages that exploit the reference +module's functionality to provide multiple methods for calculating the distance between two trajectory frames. Any measure +that you implement should thus have one of these wrapper actions associated with it and the documentation for the measure +should be included in the wrapper code's source code file. +*/ diff --git a/developer-doc/Doxyfile b/developer-doc/Doxyfile index dcf741eb8b07197109ddb9ba8cd8268bf2abe79a..693d93b7c4f524f35fe2b966f681c0080bd338ec 100644 --- a/developer-doc/Doxyfile +++ b/developer-doc/Doxyfile @@ -742,7 +742,8 @@ INPUT = ./Intro.txt \ ./AddingAColvar.txt \ ./AddingAFunction.txt \ ./AddingACLTool.txt \ - ./AddingAMultColvar.txt + ./AddingAMeasure.txt \ + ./AddingAMultColvar.txt # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/src/reference/ReferenceConfiguration.h b/src/reference/ReferenceConfiguration.h index 37509736bc5dcdd5ff302100f9cd19cd89f7dbae..a339936af42d1d6d6710504321f4a4203ea9fc64 100644 --- a/src/reference/ReferenceConfiguration.h +++ b/src/reference/ReferenceConfiguration.h @@ -38,14 +38,6 @@ class Pbc; class OFile; class PDB; -/// \ingroup TOOLBOX -/// Abstract base class for calculating the distance from a reference configuration. -/// A reference configuration can either have a particular set of atoms in a particular -/// given configuration or it can be that a particular set of colvars have a particular -/// set of values. It could also be a combination of both. To allow all the posible -/// permutations and in order make it easy to add new ways of calculating the distance -/// we have implemented this using polymorphism and multiple inheritance. - class ReferenceConfigurationOptions { friend class ReferenceConfiguration; private: @@ -56,6 +48,16 @@ public: std::string getMultiRMSDType() const ; }; +/// \ingroup INHERIT +/// Abstract base class for calculating the distance from a reference configuration. +/// A reference configuration can either have a particular set of atoms in a particular +/// given configuration or it can be that a particular set of colvars have a particular +/// set of values. It could also be a combination of both. To allow all the posible +/// permutations and in order make it easy to add new ways of calculating the distance +/// we have implemented this using polymorphism and multiple inheritance. The following +/// provides \ref AddingAMetric "information" on how to implement a new method for +/// calculating the distance between a pair of configurations + class ReferenceConfiguration { friend class SingleDomainRMSD; friend double distance( const Pbc& pbc, const std::vector<Value*> & vals, ReferenceConfiguration*, ReferenceConfiguration*, const bool& squared );