diff --git a/src/adjmat/BridgeMatrix.cpp b/src/adjmat/BridgeMatrix.cpp index 7d049a8874..50968fedd8 100644 --- a/src/adjmat/BridgeMatrix.cpp +++ b/src/adjmat/BridgeMatrix.cpp @@ -75,10 +75,13 @@ void BridgeMatrix::registerKeywords( Keywords& keys ) { keys.add("atoms","BRIDGING_ATOMS","The list of atoms that can form the bridge between the two interesting parts " "of the structure."); keys.add("optional","SWITCH","The parameters of the two switchingfunction in the above formula"); + keys.linkActionInDocs("SWITCH","LESS_THAN"); keys.add("optional","SWITCHA","The switchingfunction on the distance between bridging atoms and the atoms in " "group A"); + keys.linkActionInDocs("SWITCHA","LESS_THAN"); keys.add("optional","SWITCHB","The switchingfunction on the distance between the bridging atoms and the atoms in " "group B"); + keys.linkActionInDocs("SWITCHB","LESS_THAN"); } BridgeMatrix::BridgeMatrix(const ActionOptions&ao): diff --git a/src/adjmat/ContactMatrix.cpp b/src/adjmat/ContactMatrix.cpp index 1f6b8c0df3..cb6fe0bf7d 100644 --- a/src/adjmat/ContactMatrix.cpp +++ b/src/adjmat/ContactMatrix.cpp @@ -86,6 +86,7 @@ void ContactMatrix::registerKeywords( Keywords& keys ) { keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " "The following provides information on the \\ref switchingfunction that are available. " "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + keys.linkActionInDocs("SWITCH","LESS_THAN"); } ContactMatrix::ContactMatrix( const ActionOptions& ao ): diff --git a/src/adjmat/ContactMatrixShortcut.cpp b/src/adjmat/ContactMatrixShortcut.cpp index 70682bdb68..419d2527b2 100644 --- a/src/adjmat/ContactMatrixShortcut.cpp +++ b/src/adjmat/ContactMatrixShortcut.cpp @@ -77,6 +77,7 @@ void ContactMatrixShortcut::registerKeywords(Keywords& keys) { keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("numbered","SWITCH","specify the switching function to use between two sets of indistinguishable atoms"); + keys.linkActionInDocs("SWITCH","LESS_THAN"); keys.addActionNameSuffix("_PROPER"); keys.needsAction("TRANSPOSE"); keys.needsAction("CONCATENATE"); } diff --git a/src/adjmat/DistanceMatrix.cpp b/src/adjmat/DistanceMatrix.cpp index e224f2ee84..5b42275123 100644 --- a/src/adjmat/DistanceMatrix.cpp +++ b/src/adjmat/DistanceMatrix.cpp @@ -21,7 +21,6 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ #include "AdjacencyMatrixBase.h" #include "core/ActionRegister.h" -#include "tools/SwitchingFunction.h" #include "tools/Matrix.h" //+PLUMEDOC MATRIX DISTANCE_MATRIX diff --git a/src/adjmat/HbondMatrix.cpp b/src/adjmat/HbondMatrix.cpp index acb779720a..2d0997d097 100644 --- a/src/adjmat/HbondMatrix.cpp +++ b/src/adjmat/HbondMatrix.cpp @@ -101,10 +101,13 @@ void HbondMatrix::registerKeywords( Keywords& keys ) { keys.add("atoms","HYDROGENS","The list of atoms that can form the bridge between the two interesting parts " "of the structure."); keys.add("numbered","SWITCH","The switchingfunction that specifies how close a pair of atoms must be together for there to be a hydrogen bond between them"); + keys.linkActionInDocs("SWITCH","LESS_THAN"); keys.add("numbered","HSWITCH","The switchingfunction that specifies how close the hydrogen must be to the donor atom of the hydrogen bond for it to be " "considered a hydrogen bond"); + keys.linkActionInDocs("HSWITCH","LESS_THAN"); keys.add("numbered","ASWITCH","A switchingfunction that is used to specify what the angle between the vector connecting the donor atom to the acceptor atom and " "the vector connecting the donor atom to the hydrogen must be in order for it considered to be a hydrogen bond"); + keys.linkActionInDocs("ASWITCH","LESS_THAN"); } HbondMatrix::HbondMatrix(const ActionOptions&ao): diff --git a/src/adjmat/TopologyMatrix.cpp b/src/adjmat/TopologyMatrix.cpp index 4234c24ddb..d315689a34 100644 --- a/src/adjmat/TopologyMatrix.cpp +++ b/src/adjmat/TopologyMatrix.cpp @@ -72,10 +72,14 @@ void TopologyMatrix::registerKeywords( Keywords& keys ) { keys.add("compulsory","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " "The following provides information on the \\ref switchingfunction that are available. " "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + keys.linkActionInDocs("SWITCH","LESS_THAN"); keys.add("compulsory","RADIUS",""); + keys.linkActionInDocs("RADIUS","LESS_THAN"); keys.add("compulsory","CYLINDER_SWITCH","a switching function on ( r_ij . r_ik - 1 )/r_ij"); + keys.linkActionInDocs("CYLINDER_SWITCH","LESS_THAN"); keys.add("compulsory","BIN_SIZE","the size to use for the bins"); keys.add("compulsory","DENSITY_THRESHOLD",""); + keys.linkActionInDocs("DENSITY_THRESHOLD","LESS_THAN"); keys.add("compulsory","SIGMA","the width of the function to be used for kernel density estimation"); keys.add("compulsory","KERNEL","gaussian","the type of kernel function to be used"); } diff --git a/src/cltools/GenJson.cpp b/src/cltools/GenJson.cpp index 8c9adec6ce..22de045af7 100644 --- a/src/cltools/GenJson.cpp +++ b/src/cltools/GenJson.cpp @@ -52,6 +52,7 @@ class GenJson : public CLTool { private: std::string version; void printHyperlink(std::string action ); + void printKeywordDocs( const std::string& k, const std::string& mydescrip, const Keywords& keys ); public: static void registerKeywords( Keywords& keys ); explicit GenJson(const CLToolOptions& co ); @@ -90,6 +91,10 @@ void GenJson::printHyperlink( std::string action ) { std::cout<<".html\","<0 ) std::cout<<" \""<0 ) std::cout<<" \""<0 ) { + printKeywordDocs( keys.getKeyword(j), mydescrip, keys ); std::cout<<", \"argtype\": \""<0 ) { + printKeywordDocs( keys.getKeyword(j), mydescrip, keys ); std::cout<<", \"default\": \""< #include diff --git a/src/function/Between.cpp b/src/function/Between.cpp index 533f778851..ae3dfe9a43 100644 --- a/src/function/Between.cpp +++ b/src/function/Between.cpp @@ -34,6 +34,57 @@ namespace function { /* Use a switching function to determine how many of the input variables are within a certain range. +If we have multiple instances of a variable we can estimate the probability density function +for that variable using a process called kernel density estimation: + +\f[ +P(s) = \sum_i K\left( \frac{s - s_i}{w} \right) +\f] + +In this equation \f$K\f$ is a symmetric function that must integrate to one that is often +called a kernel function and \f$w\f$ is a smearing parameter. From a probability density function calculated using +kernel density estimation we can calculate the number/fraction of values between an upper and lower +bound using: + +\f[ +w(s) = \int_a^b \sum_i K\left( \frac{s - s_i}{w} \right) +\f] + +All the input to calculate a quantity like \f$w(s)\f$ is generally provided through a single +keyword that will have the following form: + +KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ SMEAR=\f$\frac{w}{b-a}\f$} + +This will calculate the number of values between \f$a\f$ and \f$b\f$. To calculate +the fraction of values you add the word NORM to the input specification. If the +function keyword SMEAR is not present \f$w\f$ is set equal to \f$0.5(b-a)\f$. Finally, +type should specify one of the kernel types that is present in plumed. These are listed +in the table below: + + + + + + + + + +
TYPE FUNCTION
GAUSSIAN \f$\frac{1}{\sqrt{2\pi}w} \exp\left( -\frac{(s-s_i)^2}{2w^2} \right)\f$
TRIANGULAR \f$ \frac{1}{2w} \left( 1. - \left| \frac{s-s_i}{w} \right| \right) \quad \frac{s-s_i}{w}<1 \f$
+ +Some keywords can also be used to calculate a discrete version of the histogram. That +is to say the number of values between \f$a\f$ and \f$b\f$, the number of values between +\f$b\f$ and \f$c\f$ and so on. A keyword that specifies this sort of calculation would look +something like + +KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ NBINS=\f$n\f$ SMEAR=\f$\frac{w}{n(b-a)}\f$} + +This specification would calculate the following vector of quantities: + +\f[ +w_j(s) = \int_{a + \frac{j-1}{n}(b-a)}^{a + \frac{j}{n}(b-a)} \sum_i K\left( \frac{s - s_i}{w} \right) +\f] + + \par Examples */ diff --git a/src/function/LessThan.cpp b/src/function/LessThan.cpp index 844cec1cbc..0a8c42301a 100644 --- a/src/function/LessThan.cpp +++ b/src/function/LessThan.cpp @@ -34,6 +34,143 @@ namespace function { /* Use a switching function to determine how many of the input variables are less than a certain cutoff. +Switching functions \f$s(r)\f$ take a minimum of one input parameter \f$r_0\f$. +For \f$r \le d_0 \quad s(r)=1.0\f$ while for \f$r > d_0\f$ the function decays smoothly to 0. +The various switching functions available in PLUMED differ in terms of how this decay is performed. + +Where there is an accepted convention in the literature (e.g. \ref COORDINATION) on the form of the +switching function we use the convention as the default. However, the flexibility to use different +switching functions is always present generally through a single keyword. This keyword generally +takes an input with the following form: + +\verbatim +KEYWORD={TYPE } +\endverbatim + +The following table contains a list of the various switching functions that are available in PLUMED 2 +together with an example input. + + + + + + + + + + + + + + + + + + + + + + +
TYPE FUNCTION EXAMPLE INPUT DEFAULT PARAMETERS
RATIONAL +\f$ +s(r)=\frac{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{n} }{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{m} } +\f$ + +{RATIONAL R_0=\f$r_0\f$ D_0=\f$d_0\f$ NN=\f$n\f$ MM=\f$m\f$} + \f$d_0=0.0\f$, \f$n=6\f$, \f$m=2n\f$
EXP +\f$ +s(r)=\exp\left(-\frac{ r - d_0 }{ r_0 }\right) +\f$ + +{EXP R_0=\f$r_0\f$ D_0=\f$d_0\f$} + \f$d_0=0.0\f$
GAUSSIAN +\f$ +s(r)=\exp\left(-\frac{ (r - d_0)^2 }{ 2r_0^2 }\right) +\f$ + +{GAUSSIAN R_0=\f$r_0\f$ D_0=\f$d_0\f$} + \f$d_0=0.0\f$
SMAP +\f$ +s(r) = \left[ 1 + ( 2^{a/b} -1 )\left( \frac{r-d_0}{r_0} \right)^a \right]^{-b/a} +\f$ + +{SMAP R_0=\f$r_0\f$ D_0=\f$d_0\f$ A=\f$a\f$ B=\f$b\f$} + \f$d_0=0.0\f$
Q +\f$ +s(r) = \frac{1}{1 + \exp(\beta(r_{ij} - \lambda r_{ij}^0))} +\f$ + +{Q REF=\f$r_{ij}^0\f$ BETA=\f$\beta\f$ LAMBDA=\f$\lambda\f$ } + \f$\lambda=1.8\f$, \f$\beta=50 nm^-1\f$ (all-atom)
\f$\lambda=1.5\f$, \f$\beta=50 nm^-1\f$ (coarse-grained)
CUBIC +\f$ +s(r) = (y-1)^2(1+2y) \qquad \textrm{where} \quad y = \frac{r - r_1}{r_0-r_1} +\f$ + +{CUBIC D_0=\f$r_1\f$ D_MAX=\f$r_0\f$} +
TANH +\f$ +s(r) = 1 - \tanh\left( \frac{ r - d_0 }{ r_0 } \right) +\f$ + +{TANH R_0=\f$r_0\f$ D_0=\f$d_0\f$} +
COSINUS +\f$s(r) =\left\{\begin{array}{ll} + 1 & \mathrm{if } r \leq d_0 \\ + 0.5 \left( \cos ( \frac{ r - d_0 }{ r_0 } \pi ) + 1 \right) & \mathrm{if } d_0 < r\leq d_0 + r_0 \\ + 0 & \mathrm{if } r > d_0 + r_0 + \end{array}\right. +\f$ + +{COSINUS R_0=\f$r_0\f$ D_0=\f$d_0\f$} +
CUSTOM +\f$ +s(r) = FUNC +\f$ + +{CUSTOM FUNC=1/(1+x^6) R_0=\f$r_0\f$ D_0=\f$d_0\f$} +
+ +Notice that most commonly used rational functions are better optimized and might run faster. + +Notice that for backward compatibility we allow using `MATHEVAL` instead of `CUSTOM`. +Also notice that if the a `CUSTOM` switching function only depends on even powers of `x` it can be +made faster by using `x2` as a variable. For instance +\verbatim +{CUSTOM FUNC=1/(1+x2^3) R_0=0.3} +\endverbatim +is equivalent to +\verbatim +{CUSTOM FUNC=1/(1+x^6) R_0=0.3} +\endverbatim +but runs faster. The reason is that there is an expensive square root calculation that can be optimized out. + + +\attention +With the default implementation CUSTOM is slower than other functions +(e.g., it is slower than an equivalent RATIONAL function by approximately a factor 2). +Checkout page \ref Lepton to see how to improve its performance. + +For all the switching functions in the above table one can also specify a further (optional) parameter using the parameter +keyword D_MAX to assert that for \f$r>d_{\textrm{max}}\f$ the switching function can be assumed equal to zero. +In this case the function is brought smoothly to zero by stretching and shifting it. +\verbatim +KEYWORD={RATIONAL R_0=1 D_MAX=3} +\endverbatim +the resulting switching function will be +\f$ +s(r) = \frac{s'(r)-s'(d_{max})}{s'(0)-s'(d_{max})} +\f$ +where +\f$ +s'(r)=\frac{1-r^6}{1-r^{12}} +\f$ +Since PLUMED 2.2 this is the default. The old behavior (no stretching) can be obtained with the +NOSTRETCH flag. The NOSTRETCH keyword is only provided for backward compatibility and might be +removed in the future. Similarly, the STRETCH keyword is still allowed but has no effect. + +Notice that switching functions defined with the simplified syntax are never stretched +for backward compatibility. This might change in the future. + \par Examples */ diff --git a/src/multicolvar/MultiColvarShortcuts.cpp b/src/multicolvar/MultiColvarShortcuts.cpp index ac8514999d..75da8b296b 100644 --- a/src/multicolvar/MultiColvarShortcuts.cpp +++ b/src/multicolvar/MultiColvarShortcuts.cpp @@ -31,10 +31,12 @@ void MultiColvarShortcuts::shortcutKeywords( Keywords& keys ) { keys.add("numbered","LESS_THAN","calculate the number of variables that are less than a certain target value. " "This quantity is calculated using \\f$\\sum_i \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ " "is a \\ref switchingfunction."); + keys.linkActionInDocs("LESS_THAN","LESS_THAN"); keys.addOutputComponent("lessthan","LESS_THAN","scalar","the number of colvars that have a value less than a threshold"); keys.add("numbered","MORE_THAN","calculate the number of variables that are more than a certain target value. " "This quantity is calculated using \\f$\\sum_i 1 - \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ " "is a \\ref switchingfunction."); + keys.linkActionInDocs("MORE_THAN","MORE_THAN"); keys.addOutputComponent("morethan","MORE_THAN","scalar","the number of colvars that have a value more than a threshold"); keys.add("optional","ALT_MIN","calculate the minimum value. " "To make this quantity continuous the minimum is calculated using " @@ -54,6 +56,7 @@ void MultiColvarShortcuts::shortcutKeywords( Keywords& keys ) { keys.add("numbered","BETWEEN","calculate the number of values that are within a certain range. " "These quantities are calculated using kernel density estimation as described on " "\\ref histogrambead."); + keys.linkActionInDocs("BETWEEN","BETWEEN"); keys.addOutputComponent("between","BETWEEN","scalar","the number of colvars that have a value that lies in a particular interval"); keys.addFlag("HIGHEST",false,"this flag allows you to recover the highest of these variables."); keys.addOutputComponent("highest","HIGHEST","scalar","the largest of the colvars"); diff --git a/src/secondarystructure/SecondaryStructureRMSD.cpp b/src/secondarystructure/SecondaryStructureRMSD.cpp index e360c1ce3b..d66d9bd161 100644 --- a/src/secondarystructure/SecondaryStructureRMSD.cpp +++ b/src/secondarystructure/SecondaryStructureRMSD.cpp @@ -83,6 +83,7 @@ void SecondaryStructureRMSD::registerKeywords( Keywords& keys ) { keys.addFlag("VERBOSE",false,"write a more detailed output"); keys.add("optional","LESS_THAN","calculate the number of a residue segments that are within a certain target distance of this secondary structure type. " "This quantity is calculated using \\f$\\sum_i \\sigma(s_i)\\f$, where \\f$\\sigma(s)\\f$ is a \\ref switchingfunction."); + keys.linkActionInDocs("LESS_THAN","LESS_THAN"); keys.add("optional","R_0","The r_0 parameter of the switching function."); keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","NN","8","The n parameter of the switching function"); diff --git a/src/symfunc/CoordinationNumbers.cpp b/src/symfunc/CoordinationNumbers.cpp index 9e54c9ef08..ef664f9603 100644 --- a/src/symfunc/CoordinationNumbers.cpp +++ b/src/symfunc/CoordinationNumbers.cpp @@ -110,6 +110,7 @@ void CoordinationNumbers::shortcutKeywords( Keywords& keys ) { keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function"); keys.add("compulsory","R_0","The r_0 parameter of the switching function"); keys.add("optional","SWITCH","the switching function that it used in the construction of the contact matrix"); + keys.linkActionInDocs("SWITCH","LESS_THAN"); multicolvar::MultiColvarShortcuts::shortcutKeywords( keys ); keys.needsAction("CONTACT_MATRIX"); keys.needsAction("GROUP"); } diff --git a/src/symfunc/SMAC.cpp b/src/symfunc/SMAC.cpp index 1fd6632a12..989207333a 100644 --- a/src/symfunc/SMAC.cpp +++ b/src/symfunc/SMAC.cpp @@ -55,8 +55,10 @@ void SMAC::registerKeywords(Keywords& keys) { keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. " "The following provides information on the \\ref switchingfunction that are available. " "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords."); + keys.linkActionInDocs("SWITCH","LESS_THAN"); keys.add("numbered","KERNEL","The kernels used in the function of the angle"); keys.add("optional","SWITCH_COORD","This keyword is used to define the coordination switching function."); + keys.linkActionInDocs("SWITCH_COORD","LESS_THAN"); keys.reset_style("KERNEL","optional"); keys.setValueDescription("vector","the value of the smac parameter for each of the input molecules"); multicolvar::MultiColvarShortcuts::shortcutKeywords( keys ); diff --git a/src/tools/HistogramBead.cpp b/src/tools/HistogramBead.cpp index eec7d7a312..b55d29e9a8 100644 --- a/src/tools/HistogramBead.cpp +++ b/src/tools/HistogramBead.cpp @@ -27,63 +27,6 @@ namespace PLMD { -//+PLUMEDOC INTERNAL histogrambead -/* -A function that can be used to calculate whether quantities are between fixed upper and lower bounds. - -If we have multiple instances of a variable we can estimate the probability density function -for that variable using a process called kernel density estimation: - -\f[ -P(s) = \sum_i K\left( \frac{s - s_i}{w} \right) -\f] - -In this equation \f$K\f$ is a symmetric function that must integrate to one that is often -called a kernel function and \f$w\f$ is a smearing parameter. From a probability density function calculated using -kernel density estimation we can calculate the number/fraction of values between an upper and lower -bound using: - -\f[ -w(s) = \int_a^b \sum_i K\left( \frac{s - s_i}{w} \right) -\f] - -All the input to calculate a quantity like \f$w(s)\f$ is generally provided through a single -keyword that will have the following form: - -KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ SMEAR=\f$\frac{w}{b-a}\f$} - -This will calculate the number of values between \f$a\f$ and \f$b\f$. To calculate -the fraction of values you add the word NORM to the input specification. If the -function keyword SMEAR is not present \f$w\f$ is set equal to \f$0.5(b-a)\f$. Finally, -type should specify one of the kernel types that is present in plumed. These are listed -in the table below: - - - - - - - - - -
TYPE FUNCTION
GAUSSIAN \f$\frac{1}{\sqrt{2\pi}w} \exp\left( -\frac{(s-s_i)^2}{2w^2} \right)\f$
TRIANGULAR \f$ \frac{1}{2w} \left( 1. - \left| \frac{s-s_i}{w} \right| \right) \quad \frac{s-s_i}{w}<1 \f$
- -Some keywords can also be used to calculate a discrete version of the histogram. That -is to say the number of values between \f$a\f$ and \f$b\f$, the number of values between -\f$b\f$ and \f$c\f$ and so on. A keyword that specifies this sort of calculation would look -something like - -KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ NBINS=\f$n\f$ SMEAR=\f$\frac{w}{n(b-a)}\f$} - -This specification would calculate the following vector of quantities: - -\f[ -w_j(s) = \int_{a + \frac{j-1}{n}(b-a)}^{a + \frac{j}{n}(b-a)} \sum_i K\left( \frac{s - s_i}{w} \right) -\f] - -*/ -//+ENDPLUMEDOC - void HistogramBead::registerKeywords( Keywords& keys ) { keys.add("compulsory","LOWER","the lower boundary for this particular bin"); keys.add("compulsory","UPPER","the upper boundary for this particular bin"); diff --git a/src/tools/Keywords.cpp b/src/tools/Keywords.cpp index ca9af95d6e..92e7e643da 100644 --- a/src/tools/Keywords.cpp +++ b/src/tools/Keywords.cpp @@ -38,8 +38,6 @@ Keywords::KeyType::KeyType( const std::string& type ) { style=atoms; } else if( type=="hidden" ) { style=hidden; - } else if( type=="vessel" ) { - style=vessel; } else { plumed_massert(false,"invalid keyword specifier " + type); } @@ -56,8 +54,6 @@ void Keywords::KeyType::setStyle( const std::string& type ) { style=atoms; } else if( type=="hidden" ) { style=hidden; - } else if( type=="vessel" ) { - style=vessel; } else { plumed_massert(false,"invalid keyword specifier " + type); } @@ -68,55 +64,6 @@ std::string Keywords::getStyle( const std::string & k ) const { return (types.find(k)->second).toString(); } -void Keywords::add( const Keywords& newkeys ) { - newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs ); -} - -void Keywords::copyData( std::vector& kk, std::vector& rk, std::map& tt, std::map& am, - std::map& docs, std::map& bools, std::map& nums, - std::map& atags, std::vector& cnam, std::map& ck, - std::map& cd ) const { - for(unsigned i=0; i( thiskey,types.find(thiskey)->second) ); - if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair( thiskey,atomtags.find(thiskey)->second) ); - plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" ); - am.insert( std::pair(thiskey,allowmultiple.find(thiskey)->second) ); - plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" ); - docs.insert( std::pair(thiskey,documentation.find(thiskey)->second) ); - if( booldefs.count( thiskey ) ) bools.insert( std::pair( thiskey,booldefs.find(thiskey)->second) ); - if( numdefs.count( thiskey ) ) nums.insert( std::pair( thiskey,numdefs.find(thiskey)->second) ); - } - for(unsigned i=0; i( thiskey,types.find(thiskey)->second) ); - if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair( thiskey,atomtags.find(thiskey)->second) ); - plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" ); - am.insert( std::pair(thiskey,allowmultiple.find(thiskey)->second) ); - plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" ); - docs.insert( std::pair(thiskey,documentation.find(thiskey)->second) ); - if( booldefs.count( thiskey ) ) bools.insert( std::pair( thiskey,booldefs.find(thiskey)->second) ); - if( numdefs.count( thiskey ) ) nums.insert( std::pair( thiskey,numdefs.find(thiskey)->second) ); - } - for(unsigned i=0; i( thisnam, ckey.find(thisnam)->second) ); - plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" ); - cd.insert( std::pair( thisnam, cdocs.find(thisnam)->second) ); - } -} - void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) { plumed_assert( !exists(k) && !reserved(k) ); std::string fd, lowkey=k; @@ -128,15 +75,7 @@ void Keywords::reserve( const std::string & t, const std::string & k, const std: if( num==std::string::npos ) break; lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 ); } - if( t=="vessel" ) { - fd = d + " The final value can be referenced using label." + lowkey; - if(d.find("flag")==std::string::npos) fd += ". You can use multiple instances of this keyword i.e. " + - k +"1, " + k + "2, " + k + "3... The corresponding values are then " - "referenced using label."+ lowkey +"-1, label." + lowkey + - "-2, label." + lowkey + "-3..."; - allowmultiple.insert( std::pair(k,true) ); - types.insert( std::pair(k,KeyType("vessel")) ); - } else if( t=="numbered" ) { + if( t=="numbered" ) { fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3..."; allowmultiple.insert( std::pair(k,true) ); types.insert( std::pair(k,KeyType("optional")) ); @@ -148,6 +87,7 @@ void Keywords::reserve( const std::string & t, const std::string & k, const std: if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair(k,t) ); } documentation.insert( std::pair(k,fd) ); + linkaction.insert( std::pair(k,"none") ); reserved_keys.push_back(k); } @@ -159,6 +99,7 @@ void Keywords::reserveFlag( const std::string & k, const bool def, const std::st std::string fd,lowkey=k; std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); }); fd=defstr + d; documentation.insert( std::pair(k,fd) ); + linkaction.insert( std::pair(k,"none") ); allowmultiple.insert( std::pair(k,false) ); booldefs.insert( std::pair(k,def) ); reserved_keys.push_back(k); @@ -175,12 +116,16 @@ void Keywords::reset_style( const std::string & k, const std::string & style ) { plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" ); if( style=="numbered" ) { allowmultiple[k]=true; return; } (types.find(k)->second).setStyle(style); - if( (types.find(k)->second).isVessel() ) allowmultiple[k]=true; if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair(k,style) ); } +void Keywords::linkActionInDocs( const std::string& k, const std::string& action ) { + plumed_massert( exists(k), "no " + k + " keyword" ); + (linkaction.find(k)->second)=action; +} + void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) { - plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered"); + plumed_massert( !exists(k) && t!="flag" && !reserved(k), "keyword " + k + " has already been registered"); std::string fd; if( t=="numbered" ) { fd=d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3..."; @@ -194,6 +139,7 @@ void Keywords::add( const std::string & t, const std::string & k, const std::str } if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group"; documentation.insert( std::pair(k,fd) ); + linkaction.insert( std::pair(k,"none") ); keys.push_back(k); } @@ -208,9 +154,10 @@ void Keywords::addInputKeyword( const std::string & t, const std::string & k, co } void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ) { - plumed_massert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" ), "failing on keyword " + k ); // An optional keyword can't have a default + plumed_massert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" ), "failing in action " + thisactname + " on keyword " + k ); // An optional keyword can't have a default types.insert( std::pair(k, KeyType(t)) ); documentation.insert( std::pair(k,"( default=" + def + " ) " + d) ); + linkaction.insert( std::pair(k,"none") ); allowmultiple.insert( std::pair(k,false) ); numdefs.insert( std::pair(k,def) ); keys.push_back(k); @@ -222,6 +169,7 @@ void Keywords::addFlag( const std::string & k, const bool def, const std::string defstr="( default=off ) "; types.insert( std::pair(k,KeyType("flag")) ); documentation.insert( std::pair(k,defstr + d) ); + linkaction.insert( std::pair(k,"none") ); allowmultiple.insert( std::pair(k,false) ); booldefs.insert( std::pair(k,def) ); keys.push_back(k); @@ -242,7 +190,7 @@ void Keywords::remove( const std::string & k ) { } else break; } // Delete documentation, type and so on from the description - types.erase(k); documentation.erase(k); allowmultiple.erase(k); booldefs.erase(k); numdefs.erase(k); + types.erase(k); documentation.erase(k); linkaction.erase(k); allowmultiple.erase(k); booldefs.erase(k); numdefs.erase(k); // Remove any output comonents that this keyword creates for(const auto& dkey : ckey ) { if( dkey.second==k ) removeOutputComponent( dkey.first ); @@ -443,7 +391,7 @@ void Keywords::print_html() const { } nkeys=0; for(unsigned i=0; isecond).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; + if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() ) nkeys++; } if( nkeys>0 ) { if(isaction) std::cout<<"\\par Options\n\n"; @@ -456,11 +404,11 @@ void Keywords::print_html() const { } nkeys=0; for(unsigned i=0; isecond).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; + if ( (types.find(keys[i])->second).isOptional() ) nkeys++; } if( nkeys>0 ) { for(unsigned i=0; isecond).isOptional() || (types.find(keys[i])->second).isVessel() ) print_html_item( keys[i] ); + if ( (types.find(keys[i])->second).isOptional() ) print_html_item( keys[i] ); } } std::cout<<"\n\n"; @@ -486,6 +434,10 @@ std::string Keywords::getKeywordDocs( const std::string& key ) const { sstr<<"\n"; return sstr.str(); } +std::string Keywords::getLinkedActions( const std::string& key ) const { + plumed_assert( exists( key ) ); return linkaction.find(key)->second; +} + std::string Keywords::getHelpString() const { std::string helpstr; unsigned nkeys=0; for(unsigned i=0; isecond).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++; + if ( (types.find(keys[i])->second).isOptional() ) nkeys++; } if( nkeys>0 ) { for(unsigned i=0; isecond).isOptional() || (types.find(keys[i])->second).isVessel() ) helpstr += getKeywordDocs( keys[i] ); + if ( (types.find(keys[i])->second).isOptional() ) helpstr += getKeywordDocs( keys[i] ); } helpstr += "\n"; } @@ -595,7 +547,7 @@ bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const void Keywords::destroyData() { keys.clear(); reserved_keys.clear(); types.clear(); - allowmultiple.clear(); documentation.clear(); + allowmultiple.clear(); documentation.clear(); linkaction.clear(); booldefs.clear(); numdefs.clear(); atomtags.clear(); ckey.clear(); cdocs.clear(); ckey.clear(); } diff --git a/src/tools/Keywords.h b/src/tools/Keywords.h index efce8b38a0..09bc79d6b1 100644 --- a/src/tools/Keywords.h +++ b/src/tools/Keywords.h @@ -37,21 +37,19 @@ class Keywords { /// This class lets me pass keyword types easily class KeyType { public: - enum {hidden,compulsory,flag,optional,atoms,vessel} style; + enum {hidden,compulsory,flag,optional,atoms} style; explicit KeyType( const std::string& type ); void setStyle( const std::string& type ); bool isCompulsory() const { return (style==compulsory); } bool isFlag() const { return (style==flag); } bool isOptional() const { return (style==optional); } bool isAtomList() const { return (style==atoms); } - bool isVessel() const { return (style==vessel); } std::string toString() const { if(style==compulsory) return "compulsory"; else if(style==optional) return "optional"; else if(style==atoms) return "atoms"; else if(style==flag) return "flag"; else if(style==hidden) return "hidden"; - else if(style==vessel) return "vessel"; else plumed_assert(0); return ""; } @@ -76,6 +74,8 @@ class Keywords { std::map allowmultiple; /// The documentation for the keywords std::map documentation; +/// This stores any action documentation that we should link to + std::map linkaction; /// The type for the arguments in this action std::map argument_types; /// The default values for the flags (are they on or of) @@ -119,6 +119,8 @@ class Keywords { std::string getKeyword( const unsigned i ) const ; /// Get the documentation for a particular keyword std::string getKeywordDocs( const std::string& key ) const ; +/// Get any actions that are linked to this keyword + std::string getLinkedActions( const std::string& key ) const ; /// Print the documentation to the log file (used by PLMD::Action::error) void print( Log& log ) const ; /// Print the documentation to a file (use by PLUMED::CLTool::readCommandLineArgs) @@ -141,6 +143,8 @@ class Keywords { void add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ); /// Add a falg with name k that is by default on if def is true and off if def is false. d should provide a description of the flag void addFlag( const std::string & k, const bool def, const std::string & d ); +/// Create a link to this action in the documentation for it + void linkActionInDocs( const std::string& k, const std::string& action ); /// Remove the keyword with name k void remove( const std::string & k ); /// Check if there is a keyword with name k @@ -159,13 +163,6 @@ class Keywords { void print_template( const std::string& actionname, bool include_optional) const ; /// Change the style of a keyword void reset_style( const std::string & k, const std::string & style ); -/// Add keywords from one keyword object to another - void add( const Keywords& keys ); -/// Copy the keywords data - void copyData( std::vector& kk, std::vector& rk, std::map& tt, std::map& am, - std::map& docs, std::map& bools, std::map& nums, - std::map& atags, std::vector& cnam, std::map& ck, - std::map& cd ) const ; /// Clear everything from the keywords object. /// Not actually needed if your Keywords object is going out of scope. void destroyData(); diff --git a/src/tools/SwitchingFunction.cpp b/src/tools/SwitchingFunction.cpp index 3339c2ec3b..a20e29d57e 100644 --- a/src/tools/SwitchingFunction.cpp +++ b/src/tools/SwitchingFunction.cpp @@ -30,150 +30,6 @@ namespace PLMD { -//+PLUMEDOC INTERNAL switchingfunction -/* -Functions that measure whether values are less than a certain quantity. - -Switching functions \f$s(r)\f$ take a minimum of one input parameter \f$r_0\f$. -For \f$r \le d_0 \quad s(r)=1.0\f$ while for \f$r > d_0\f$ the function decays smoothly to 0. -The various switching functions available in PLUMED differ in terms of how this decay is performed. - -Where there is an accepted convention in the literature (e.g. \ref COORDINATION) on the form of the -switching function we use the convention as the default. However, the flexibility to use different -switching functions is always present generally through a single keyword. This keyword generally -takes an input with the following form: - -\verbatim -KEYWORD={TYPE } -\endverbatim - -The following table contains a list of the various switching functions that are available in PLUMED 2 -together with an example input. - - - - - - - - - - - - - - - - - - - - - - -
TYPE FUNCTION EXAMPLE INPUT DEFAULT PARAMETERS
RATIONAL -\f$ -s(r)=\frac{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{n} }{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{m} } -\f$ - -{RATIONAL R_0=\f$r_0\f$ D_0=\f$d_0\f$ NN=\f$n\f$ MM=\f$m\f$} - \f$d_0=0.0\f$, \f$n=6\f$, \f$m=2n\f$
EXP -\f$ -s(r)=\exp\left(-\frac{ r - d_0 }{ r_0 }\right) -\f$ - -{EXP R_0=\f$r_0\f$ D_0=\f$d_0\f$} - \f$d_0=0.0\f$
GAUSSIAN -\f$ -s(r)=\exp\left(-\frac{ (r - d_0)^2 }{ 2r_0^2 }\right) -\f$ - -{GAUSSIAN R_0=\f$r_0\f$ D_0=\f$d_0\f$} - \f$d_0=0.0\f$
SMAP -\f$ -s(r) = \left[ 1 + ( 2^{a/b} -1 )\left( \frac{r-d_0}{r_0} \right)^a \right]^{-b/a} -\f$ - -{SMAP R_0=\f$r_0\f$ D_0=\f$d_0\f$ A=\f$a\f$ B=\f$b\f$} - \f$d_0=0.0\f$
Q -\f$ -s(r) = \frac{1}{1 + \exp(\beta(r_{ij} - \lambda r_{ij}^0))} -\f$ - -{Q REF=\f$r_{ij}^0\f$ BETA=\f$\beta\f$ LAMBDA=\f$\lambda\f$ } - \f$\lambda=1.8\f$, \f$\beta=50 nm^-1\f$ (all-atom)
\f$\lambda=1.5\f$, \f$\beta=50 nm^-1\f$ (coarse-grained)
CUBIC -\f$ -s(r) = (y-1)^2(1+2y) \qquad \textrm{where} \quad y = \frac{r - r_1}{r_0-r_1} -\f$ - -{CUBIC D_0=\f$r_1\f$ D_MAX=\f$r_0\f$} -
TANH -\f$ -s(r) = 1 - \tanh\left( \frac{ r - d_0 }{ r_0 } \right) -\f$ - -{TANH R_0=\f$r_0\f$ D_0=\f$d_0\f$} -
COSINUS -\f$s(r) =\left\{\begin{array}{ll} - 1 & \mathrm{if } r \leq d_0 \\ - 0.5 \left( \cos ( \frac{ r - d_0 }{ r_0 } \pi ) + 1 \right) & \mathrm{if } d_0 < r\leq d_0 + r_0 \\ - 0 & \mathrm{if } r > d_0 + r_0 - \end{array}\right. -\f$ - -{COSINUS R_0=\f$r_0\f$ D_0=\f$d_0\f$} -
CUSTOM -\f$ -s(r) = FUNC -\f$ - -{CUSTOM FUNC=1/(1+x^6) R_0=\f$r_0\f$ D_0=\f$d_0\f$} -
- -Notice that most commonly used rational functions are better optimized and might run faster. - -Notice that for backward compatibility we allow using `MATHEVAL` instead of `CUSTOM`. -Also notice that if the a `CUSTOM` switching function only depends on even powers of `x` it can be -made faster by using `x2` as a variable. For instance -\verbatim -{CUSTOM FUNC=1/(1+x2^3) R_0=0.3} -\endverbatim -is equivalent to -\verbatim -{CUSTOM FUNC=1/(1+x^6) R_0=0.3} -\endverbatim -but runs faster. The reason is that there is an expensive square root calculation that can be optimized out. - - -\attention -With the default implementation CUSTOM is slower than other functions -(e.g., it is slower than an equivalent RATIONAL function by approximately a factor 2). -Checkout page \ref Lepton to see how to improve its performance. - -For all the switching functions in the above table one can also specify a further (optional) parameter using the parameter -keyword D_MAX to assert that for \f$r>d_{\textrm{max}}\f$ the switching function can be assumed equal to zero. -In this case the function is brought smoothly to zero by stretching and shifting it. -\verbatim -KEYWORD={RATIONAL R_0=1 D_MAX=3} -\endverbatim -the resulting switching function will be -\f$ -s(r) = \frac{s'(r)-s'(d_{max})}{s'(0)-s'(d_{max})} -\f$ -where -\f$ -s'(r)=\frac{1-r^6}{1-r^{12}} -\f$ -Since PLUMED 2.2 this is the default. The old behavior (no stretching) can be obtained with the -NOSTRETCH flag. The NOSTRETCH keyword is only provided for backward compatibility and might be -removed in the future. Similarly, the STRETCH keyword is still allowed but has no effect. - -Notice that switching functions defined with the simplified syntax are never stretched -for backward compatibility. This might change in the future. - -*/ -//+ENDPLUMEDOC - namespace switchContainers { baseSwitch::baseSwitch(double D0,double DMAX, double R0, std::string_view name) diff --git a/src/volumes/VolumeInCylinder.cpp b/src/volumes/VolumeInCylinder.cpp index 1253007546..aeb854031e 100644 --- a/src/volumes/VolumeInCylinder.cpp +++ b/src/volumes/VolumeInCylinder.cpp @@ -106,7 +106,7 @@ void VolumeInCylinder::registerKeywords( Keywords& keys ) { keys.add("compulsory","RADIUS","a switching function that gives the extent of the cylinder in the plane perpendicular to the direction"); keys.add("compulsory","LOWER","0.0","the lower boundary on the direction parallel to the long axis of the cylinder"); keys.add("compulsory","UPPER","0.0","the upper boundary on the direction parallel to the long axis of the cylinder"); - keys.reset_style("SIGMA","optional"); + keys.reset_style("SIGMA","optional"); keys.linkActionInDocs("RADIUS","LESS_THAN"); } VolumeInCylinder::VolumeInCylinder(const ActionOptions& ao): diff --git a/src/volumes/VolumeInSphere.cpp b/src/volumes/VolumeInSphere.cpp index 141ad4fbe7..3709bf09f8 100644 --- a/src/volumes/VolumeInSphere.cpp +++ b/src/volumes/VolumeInSphere.cpp @@ -100,7 +100,7 @@ void VolumeInSphere::registerKeywords( Keywords& keys ) { keys.add("atoms","CENTER","the atom whose vicinity we are interested in examining"); keys.add("atoms-2","ATOM","the atom whose vicinity we are interested in examining"); keys.add("compulsory","RADIUS","the switching function that tells us the extent of the sphereical region of interest"); - keys.remove("SIGMA"); + keys.remove("SIGMA"); keys.linkActionInDocs("RADIUS","LESS_THAN"); } VolumeInSphere::VolumeInSphere(const ActionOptions& ao):