diff --git a/src/adjmat/BridgeMatrix.cpp b/src/adjmat/BridgeMatrix.cpp index 9d98b3e2c8..9c864d57d6 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 91de71ef96..a3a9b4d48d 100644 --- a/src/adjmat/ContactMatrix.cpp +++ b/src/adjmat/ContactMatrix.cpp @@ -89,6 +89,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 9431c8a699..37a26967b0 100644 --- a/src/adjmat/ContactMatrixShortcut.cpp +++ b/src/adjmat/ContactMatrixShortcut.cpp @@ -78,6 +78,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 3d097bb347..199eb0bb6c 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 b799c3e1b4..65d5814b82 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 7816236fd7..5f1d69b2fa 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 f84c7781e7..c785c8e66f 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 ); @@ -108,6 +109,10 @@ void GenJson::printHyperlink( std::string action ) { std::cout<<".html\","<0 ) { - std::cout<<" \""<0 ) { - std::cout<<" \""< #include diff --git a/src/function/Between.cpp b/src/function/Between.cpp index c2c679cb77..1f1778b6fb 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 dc69d0f130..6bcace26ad 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 cf932246a9..104427dfa2 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 4c66f2e192..54f419ebf0 100644 --- a/src/secondarystructure/SecondaryStructureRMSD.cpp +++ b/src/secondarystructure/SecondaryStructureRMSD.cpp @@ -91,6 +91,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 93c373f2b2..a3f4306986 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 d5858cadd9..33a19c0e22 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 0fb95191e1..5bddcbad3a 100644 --- a/src/tools/HistogramBead.cpp +++ b/src/tools/HistogramBead.cpp @@ -25,64 +25,14 @@ #include "Tools.h" #include "Keywords.h" -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$} +IMPORTANT NOTE FOR DEVELOPERS: -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] +If you add a new type of function in this file please add documentation for your new switching function type in function/Between.cpp */ -//+ENDPLUMEDOC + +namespace PLMD { void HistogramBead::registerKeywords( Keywords& keys ) { keys.add("compulsory","LOWER","the lower boundary for this particular bin"); diff --git a/src/tools/Keywords.cpp b/src/tools/Keywords.cpp index cd52dea085..c927520f62 100644 --- a/src/tools/Keywords.cpp +++ b/src/tools/Keywords.cpp @@ -200,8 +200,6 @@ Keywords::KeyType::keyStyle Keywords::KeyType::keyStyleFromString(std::string_vi return keyStyle::atoms; } else if( type=="hidden" ) { return keyStyle::hidden; - } else if( type=="vessel" ) { - return keyStyle::vessel; } else { plumed_massert(false,"invalid keyword specifier " + std::string(type)); } @@ -248,6 +246,10 @@ Keywords::keyInfo& Keywords::keyInfo::setAllowMultiple(bool a) { allowmultiple=a; return *this; } +Keywords::keyInfo& Keywords::keyInfo::setLinkedAction(std::string_view a) { + linkaction=a; + return *this; +} bool Keywords::keyInfo::isArgument() const { return std::holds_alternative(argument_type); } @@ -312,28 +314,11 @@ void Keywords::addOrReserve( std::string_view keytype, auto type = KeyType(t_type); if (!reserve) { plumed_massert( !type.isFlag(), "use addFlag() to register a flag keyword (" + std::string(key) + ")"); - plumed_massert( !type.isVessel(), "use reserve() to register a vessel keyword (" + std::string(key) + ")"); } std::string fd{docstring}; bool allowMultiple= false; - if( type.isVessel() && reserve) { - // Convert to lower case - std::string lowkey{key}; - std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { - return std::tolower(c); - }); - // Remove any underscore characters - erase_remove(lowkey, '_'); - - fd += " The final value can be referenced using label." + lowkey; - if(docstring.find("flag")==std::string::npos) { - fd += NUMBERED_DOCSTRING(key) " The corresponding values are then " - "referenced using label."+ lowkey +"-1, label." + lowkey + - "-2, label." + lowkey + "-3..."; - } - allowMultiple = true; - } else if( isNumbered ) { + if( isNumbered ) { fd += NUMBERED_DOCSTRING(key); allowMultiple = true; } @@ -341,7 +326,8 @@ void Keywords::addOrReserve( std::string_view keytype, keywords[std::string(key)] = keyInfo() .setType(type) .setDocString(fd) - .setAllowMultiple(allowMultiple); + .setAllowMultiple(allowMultiple) + .setLinkedAction("none"); if( type.isAtomList() ) { //keytype may be "residues" or something like "atoms-3" keywords.find(key)->second.atomtag=keytype; @@ -376,7 +362,8 @@ void Keywords::reserveFlag(const std::string & key, const bool defaultValue, con .setType(KeyType{KeyType::keyStyle::flag}) .setDocString(defstr + docstring) .setAllowMultiple(false) - .setDefaultFlag(defaultValue); + .setDefaultFlag(defaultValue) + .setLinkedAction("none"); reserved_keys.emplace_back(key); } @@ -397,9 +384,6 @@ void Keywords::reset_style( const std::string & k, const std::string & style ) { return; } keywords.at(k).type.setStyle(style); - if( (keywords.at(k).type).isVessel() ) { - keywords.at(k).allowmultiple=true; - } if( (keywords.at(k).type).isAtomList() ) { keywords.at(k).atomtag=style; } @@ -466,7 +450,8 @@ void Keywords::add( std::string_view keytype, .setType(type) .setDefaultValue(defaultValue) .setDocString("( default=" + std::string(defaultValue) + " ) " + std::string(docstring) ) - .setAllowMultiple(false); + .setAllowMultiple(false) + .setLinkedAction("none"); keys.emplace_back(key); } @@ -479,7 +464,8 @@ void Keywords::addFlag(std::string_view key, bool defaultValue, std::string_view .setType(KeyType("flag")) .setDefaultFlag(false) .setDocString(std::string(defstr) + std::string(docstring)) - .setAllowMultiple(false); + .setAllowMultiple(false) + .setLinkedAction("none"); keys.emplace_back(key); } @@ -729,7 +715,7 @@ void Keywords::print_html() const { } nkeys=0; for(const auto& key : keys) { - if ( keywords.at(key).type.isFlag() || keywords.at(key).type.isOptional() || keywords.at(key).type.isVessel() ) { + if ( keywords.at(key).type.isFlag() || keywords.at(key).type.isOptional() ) { nkeys++; } } @@ -749,13 +735,13 @@ void Keywords::print_html() const { } nkeys=0; for(const auto& key : keys) { - if ( keywords.at(key).type.isOptional() || keywords.at(key).type.isVessel() ) { + if ( keywords.at(key).type.isOptional() ) { nkeys++; } } if( nkeys>0 ) { for(const auto& key : keys) { - if ( keywords.at(key).type.isOptional() || keywords.at(key).type.isVessel() ) { + if ( keywords.at(key).type.isOptional() ) { print_html_item( key ); } } @@ -845,13 +831,13 @@ std::string Keywords::getHelpString() const { } nkeys=0; for(const auto& key : keys) { - if ( keywords.at(key).type.isOptional() || keywords.at(key).type.isVessel() ) { + if ( keywords.at(key).type.isOptional() ) { nkeys++; } } if( nkeys>0 ) { for(const auto& key : keys) { - if ( keywords.at(key).type.isOptional() || keywords.at(key).type.isVessel() ) { + if ( keywords.at(key).type.isOptional() ) { helpstr += getKeywordDocs( key ); } } @@ -1173,4 +1159,14 @@ std::string Keywords::getReplacementAction() const { return replaceaction; } +void Keywords::linkActionInDocs( const std::string& k, const std::string& action ) { + plumed_massert( exists(k), "no " + k + " keyword" ); + keywords.at(k).setLinkedAction(action); +} + +std::string Keywords::getLinkedActions( const std::string& key ) const { + plumed_assert( exists( key ) ); + return keywords.at(key).linkaction; +} + }// namespace PLMD diff --git a/src/tools/Keywords.h b/src/tools/Keywords.h index 9a02e1e5cb..7b7af9e31c 100644 --- a/src/tools/Keywords.h +++ b/src/tools/Keywords.h @@ -38,7 +38,7 @@ class Log; class Keywords { /// This class lets me pass keyword types easily struct KeyType { - enum class keyStyle {hidden,compulsory,flag,optional,atoms,vessel,unknown}; + enum class keyStyle {hidden,compulsory,flag,optional,atoms,unknown}; keyStyle style; static keyStyle keyStyleFromString(std::string_view type ); explicit KeyType( keyStyle type ); @@ -56,9 +56,6 @@ class Keywords { bool isAtomList() const { return (style==keyStyle::atoms); } - bool isVessel() const { - return (style==keyStyle::vessel); - } bool isHidden() const { return (style==keyStyle::hidden); } @@ -75,8 +72,6 @@ class Keywords { return "flag"; case keyStyle::hidden: return "hidden"; - case keyStyle::vessel: - return "vessel"; default: plumed_massert(false,"unknown keyword type"); } @@ -108,6 +103,8 @@ class Keywords { std::variantargument_type; /// The tags for atoms - we use this so the manual can differentiate between different ways of specifying atoms std::string atomtag;//no noeed for optional, since the type will state if this is needed + ///This stores any action documentation that we should link to + std::string linkaction; /// Do we allow stuff like key1, key2 etc bool allowmultiple; keyInfo(); @@ -118,6 +115,7 @@ class Keywords { keyInfo& setDefaultFlag(bool a); keyInfo& setArgumentType(argType a); keyInfo& setAllowMultiple(bool a); + keyInfo& setLinkedAction(std::string_view a); bool isArgument() const; }; ///Add o reserve a new keyword (internal tool) @@ -314,6 +312,10 @@ class Keywords { std::string getReplacementAction() const ; /// Note that this action has been deprecated void setDeprecated( const std::string& name ); +/// Create a link to this action in the documentation for it + void linkActionInDocs( const std::string& k, const std::string& action ); +/// Get any actions that are linked to this keyword + std::string getLinkedActions( const std::string& key ) const ; }; //the following templates specializations make the bitmask enum work with the diff --git a/src/tools/SwitchingFunction.cpp b/src/tools/SwitchingFunction.cpp index de4ac3f8d8..97ad73f340 100644 --- a/src/tools/SwitchingFunction.cpp +++ b/src/tools/SwitchingFunction.cpp @@ -28,151 +28,13 @@ #include #include -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. +IMPORTANT NOTE FOR DEVELOPERS: +If you add a new type of switching function in this file please add documentation for your new switching function type in function/LessThan.cpp */ -//+ENDPLUMEDOC + +namespace PLMD { namespace switchContainers { diff --git a/src/volumes/VolumeInCylinder.cpp b/src/volumes/VolumeInCylinder.cpp index df439093f4..304154018b 100644 --- a/src/volumes/VolumeInCylinder.cpp +++ b/src/volumes/VolumeInCylinder.cpp @@ -108,6 +108,7 @@ void VolumeInCylinder::registerKeywords( Keywords& keys ) { 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.linkActionInDocs("RADIUS","LESS_THAN"); } VolumeInCylinder::VolumeInCylinder(const ActionOptions& ao): diff --git a/src/volumes/VolumeInSphere.cpp b/src/volumes/VolumeInSphere.cpp index 91de7e5719..f6ba489504 100644 --- a/src/volumes/VolumeInSphere.cpp +++ b/src/volumes/VolumeInSphere.cpp @@ -102,6 +102,7 @@ void VolumeInSphere::registerKeywords( Keywords& keys ) { 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.linkActionInDocs("RADIUS","LESS_THAN"); } VolumeInSphere::VolumeInSphere(const ActionOptions& ao):