Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-2019 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : 5 : See http://www.plumed.org for more information. 6 : 7 : This file is part of plumed, version 2. 8 : 9 : plumed is free software: you can redistribute it and/or modify 10 : it under the terms of the GNU Lesser General Public License as published by 11 : the Free Software Foundation, either version 3 of the License, or 12 : (at your option) any later version. 13 : 14 : plumed is distributed in the hope that it will be useful, 15 : but WITHOUT ANY WARRANTY; without even the implied warranty of 16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 : GNU Lesser General Public License for more details. 18 : 19 : You should have received a copy of the GNU Lesser General Public License 20 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 22 : #include "Function.h" 23 : #include "ActionRegister.h" 24 : #include "tools/PDB.h" 25 : #include "reference/MetricRegister.h" 26 : #include "reference/ArgumentOnlyDistance.h" 27 : #include "core/Atoms.h" 28 : #include "core/PlumedMain.h" 29 : #include <memory> 30 : 31 : using namespace std; 32 : 33 : namespace PLMD { 34 : namespace function { 35 : 36 : //+PLUMEDOC DCOLVAR TARGET 37 : /* 38 : This function measures the Pythagorean distance from a particular structure measured in the space defined by some set of collective variables. 39 : 40 : This collective variable can be used to calculate something akin to: 41 : 42 : \f[ 43 : d(X,X') = \vert X - X' \vert 44 : \f] 45 : 46 : where \f$ X \f$ is the instantaneous values for a set of collective variables for the system and 47 : \f$ X' \f$ is the values that these self-same set of collective variables take in some reference structure provided as input. 48 : If we call our set of collective variables \f$\{s_i\}\f$ then this CV computes: 49 : 50 : \f[ 51 : d = \sqrt{ \sum_{i=1}^N (s_i - s_i^{(ref)})^2 } 52 : \f] 53 : 54 : where \f$s_i^{(ref)}\f$ are the values of the CVs in the reference structure and \f$N\f$ is the number of input CVs. 55 : 56 : We can also calculate normalized euclidean differences using this action and the METRIC=NORM-EUCLIDEAN flag. In other words, 57 : we can compute: 58 : 59 : \f[ 60 : d = \sqrt{ \sum_{i=1}^N \sigma_i (s_i - s_i^{(ref)})^2 } 61 : \f] 62 : 63 : where \f$\sigma_i\f$ is a vector of weights. Lastly, by using the METRIC=MAHALONOBIS we can compute Mahalonobis distances using: 64 : 65 : \f[ 66 : d = \left( \mathbf{s} - \mathbf{s}^{(ref)} \right)^T \mathbf{\Sigma} \left( \mathbf{s} - \mathbf{s}^{(ref)} \right) 67 : \f] 68 : 69 : where \f$\mathbf{s}\f$ is a column vector containing the values of all the CVs and \f$\mathbf{s}^{(ref)}\f$ is a column vector 70 : containing the values of the CVs in the reference configuration. \f$\mathbf{\Sigma}\f$ is then an \f$N \times N\f$ matrix that is 71 : specified in the input. 72 : 73 : \par Examples 74 : 75 : The following input calculates the distance between a reference configuration and the instantaneous position of the system in the trajectory. 76 : The position of the reference configuration is specified by providing the values of the distance between atoms 1 and 2 and atoms 3 and 4. 77 : 78 : \plumedfile 79 : d1: DISTANCE ATOMS=1,2 80 : d2: DISTANCE ATOMS=3,4 81 : t1: TARGET REFERENCE=reference.pdb TYPE=EUCLIDEAN 82 : PRINT ARG=t1 FILE=colvar 83 : \endplumedfile 84 : 85 : The contents of the file containing the reference structure (reference.pdb) is shown below. As you can see you must provide information on the 86 : labels of the CVs that are being used to define the position of the reference configuration in this file together with the values that these 87 : quantities take in the reference configuration. 88 : 89 : \auxfile{reference.pdb} 90 : DESCRIPTION: a reference point. 91 : REMARK WEIGHT=1.0 92 : REMARK ARG=d1,d2 93 : REMARK d1=1.0 d2=1.0 94 : END 95 : \endauxfile 96 : 97 : */ 98 : //+ENDPLUMEDOC 99 : 100 0 : class Target : public Function { 101 : private: 102 : MultiValue myvals; 103 : ReferenceValuePack mypack; 104 : std::unique_ptr<PLMD::ArgumentOnlyDistance> target; 105 : public: 106 : explicit Target(const ActionOptions&); 107 : void calculate() override; 108 : static void registerKeywords(Keywords& keys ); 109 : }; 110 : 111 7832 : PLUMED_REGISTER_ACTION(Target,"TARGET") 112 : 113 1 : void Target::registerKeywords(Keywords& keys) { 114 1 : Function::registerKeywords(keys); 115 5 : keys.add("compulsory","TYPE","EUCLIDEAN","the manner in which the distance should be calculated"); 116 : keys.add("compulsory","REFERENCE","a file in pdb format containing the reference structure. In the PDB file the atomic " 117 : "coordinates and box lengths should be in Angstroms unless you are working with natural units. " 118 : "If you are working with natural units then the coordinates should be in your natural length unit. " 119 : "The charges and masses of the atoms (if required) should be inserted in the beta and occupancy " 120 4 : "columns respectively. For more details on the PDB file format visit http://www.wwpdb.org/docs.html"); 121 1 : } 122 : 123 0 : Target::Target(const ActionOptions&ao): 124 : Action(ao), 125 : Function(ao), 126 : myvals(1,0), 127 0 : mypack(0,0,myvals) 128 : { 129 0 : std::string type; parse("TYPE",type); 130 0 : std::string reference; parse("REFERENCE",reference); 131 0 : checkRead(); PDB pdb; 132 0 : if( !pdb.read(reference,plumed.getAtoms().usingNaturalUnits(),0.1/plumed.getAtoms().getUnits().getLength()) ) 133 0 : error("missing input file " + reference); 134 : 135 : // Use the base ActionWithArguments to expand things like a1.* 136 0 : expandArgKeywordInPDB( pdb ); 137 : 138 : // Generate the reference structure 139 0 : target=metricRegister().create<ArgumentOnlyDistance>( type, pdb ); 140 : 141 : // Get the argument names 142 0 : std::vector<std::string> args_to_retrieve; 143 0 : target->getArgumentRequests( args_to_retrieve, false ); 144 : 145 : // Get the arguments 146 : std::vector<Value*> myargs; 147 0 : interpretArgumentList( args_to_retrieve, myargs ); 148 0 : requestArguments( myargs ); 149 : 150 : // Now create packs 151 0 : myvals.resize( 1, myargs.size() ); 152 0 : mypack.resize( myargs.size(), 0 ); 153 : 154 : // Create the value 155 0 : addValueWithDerivatives(); setNotPeriodic(); 156 0 : } 157 : 158 0 : void Target::calculate() { 159 0 : mypack.clear(); double r=target->calculate( getArguments(), mypack, false ); setValue(r); 160 0 : for(unsigned i=0; i<getNumberOfArguments(); i++) setDerivative( i, mypack.getArgumentDerivative(i) ); 161 0 : } 162 : 163 : } 164 5874 : }