Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-2020 The plumed team 3 : (see the PEOPLE file at the root of the distribution for a list of names) 4 : See http://www.plumed.org for more information. 5 : This file is part of plumed, version 2. 6 : plumed is free software: you can redistribute it and/or modify 7 : it under the terms of the GNU Lesser General Public License as published by 8 : the Free Software Foundation, either version 3 of the License, or 9 : (at your option) any later version. 10 : plumed is distributed in the hope that it will be useful, 11 : but WITHOUT ANY WARRANTY; without even the implied warranty of 12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 : GNU Lesser General Public License for more details. 14 : You should have received a copy of the GNU Lesser General Public License 15 : along with plumed. If not, see <http://www.gnu.org/licenses/>. 16 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ 17 : #include "core/ActionRegister.h" 18 : #include "core/PlumedMain.h" 19 : #include "core/ActionSet.h" 20 : #include "core/ActionWithValue.h" 21 : #include "core/ActionShortcut.h" 22 : 23 : namespace PLMD { 24 : namespace colvar { 25 : 26 : //+PLUMEDOC COLVAR GYRATION 27 : /* 28 : Calculate the radius of gyration, or other properties related to it. 29 : 30 : With this version of the command you can use any property you so choose to define the weights that are used when computing the average. 31 : If you use the mass or if all the atoms are ascribed weights of one PLUMED defaults to \ref GYRATION_FAST 32 : 33 : \par Examples 34 : 35 : */ 36 : //+ENDPLUMEDOC 37 : 38 : //+PLUMEDOC MCOLVAR GYRATION_TENSOR 39 : /* 40 : Calculate the gyration tensor using a user specified vector of weights 41 : 42 : \par Examples 43 : 44 : */ 45 : //+ENDPLUMEDOC 46 : 47 : class GyrationShortcut : public ActionShortcut { 48 : public: 49 : static void registerKeywords( Keywords& keys ); 50 : explicit GyrationShortcut(const ActionOptions&); 51 : }; 52 : 53 : PLUMED_REGISTER_ACTION(GyrationShortcut,"GYRATION") 54 : PLUMED_REGISTER_ACTION(GyrationShortcut,"GYRATION_TENSOR") 55 : 56 122 : void GyrationShortcut::registerKeywords( Keywords& keys ) { 57 122 : ActionShortcut::registerKeywords( keys ); 58 244 : keys.add("atoms","ATOMS","the group of atoms that you are calculating the Gyration Tensor for"); 59 244 : keys.add("compulsory","TYPE","RADIUS","The type of calculation relative to the Gyration Tensor you want to perform"); 60 244 : keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances"); 61 244 : keys.add("optional","WEIGHTS","what weights should be used when calculating the center. If this keyword is not present the geometric center is computed. " 62 : "If WEIGHTS=@Masses is used the center of mass is computed. If WEIGHTS=@charges the center of charge is computed. If " 63 : "the label of an action is provided PLUMED assumes that that action calculates a list of symmetry functions that can be used " 64 : "as weights. Lastly, an explicit list of numbers to use as weights can be provided"); 65 244 : keys.addFlag("PHASES",false,"use trigonometric phases when computing position of center of mass"); 66 244 : keys.addFlag("MASS",false,"calculate the center of mass"); 67 244 : keys.addFlag("MASS_WEIGHTED",false,"set the masses of all the atoms equal to one"); 68 244 : keys.addFlag("UNORMALIZED",false,"do not divide by the sum of the weights"); 69 360 : if( keys.getDisplayName()=="GYRATION" ) keys.setValueDescription("scalar","the radius that was computed from the weights"); 70 18 : else if( keys.getDisplayName()=="GYRATION_TENSOR" ) keys.setValueDescription("matrix","the gyration tensor that was computed from the weights"); 71 366 : keys.addActionNameSuffix("_FAST"); keys.needsAction("CENTER"); keys.needsAction("CONSTANT"); 72 366 : keys.needsAction("ONES"); keys.needsAction("MASS"); keys.needsAction("DISTANCE"); 73 244 : keys.needsAction("COVARIANCE_MATRIX"); keys.needsAction("SELECT_COMPONENTS"); 74 366 : keys.needsAction("SUM"); keys.needsAction("CUSTOM"); keys.needsAction("DIAGONALIZE"); 75 122 : } 76 : 77 116 : GyrationShortcut::GyrationShortcut(const ActionOptions& ao): 78 : Action(ao), 79 116 : ActionShortcut(ao) 80 : { 81 348 : bool usemass, phases; parseFlag("MASS",usemass); parseFlag("PHASES",phases); 82 232 : std::vector<std::string> str_weights; parseVector("WEIGHTS",str_weights); std::string wflab; 83 116 : if( !phases ) { 84 115 : if( usemass || str_weights.size()==0 || (str_weights.size()==1 && str_weights[0]=="@Masses") ) { 85 : std::string wt_str; 86 112 : if( str_weights.size()>0 ) { 87 0 : wt_str="WEIGHTS=" + str_weights[0]; for(unsigned i=1; i<str_weights.size(); ++i) wt_str += "," + str_weights[i]; 88 : } 89 112 : if( usemass || (str_weights.size()==1 && str_weights[0]=="@Masses") ) wt_str = "MASS"; 90 232 : readInputLine( getShortcutLabel() + ": GYRATION_FAST " + wt_str + " " + convertInputLineToString() ); 91 : return; 92 : } 93 : } 94 4 : if( usemass ) { str_weights.resize(1); str_weights[0]="@Masses"; } 95 10 : log<<" Bibliography "<<plumed.cite("Jirí Vymetal and Jirí Vondrasek, J. Phys. Chem. A 115, 11455 (2011)")<<"\n"; 96 : // Read in the atoms involved 97 8 : std::vector<std::string> atoms; parseVector("ATOMS",atoms); Tools::interpretRanges(atoms); 98 12 : std::string gtype, atlist=atoms[0]; for(unsigned i=1; i<atoms.size(); ++i) atlist += "," + atoms[i]; 99 8 : bool nopbc; parseFlag("NOPBC",nopbc); std::string pbcstr; if(nopbc) pbcstr = " NOPBC"; 100 4 : std::string phasestr; if(phases) phasestr = " PHASES"; 101 : // Create the geometric center of the molecule 102 4 : std::string weights_str=" WEIGHTS=" + str_weights[0]; 103 8 : for(unsigned i=1; i<str_weights.size(); ++i) weights_str += "," + str_weights[i]; 104 8 : readInputLine( getShortcutLabel() + "_cent: CENTER ATOMS=" + atlist + pbcstr + phasestr + weights_str ); 105 4 : if( str_weights.size()==0 ) { 106 0 : wflab = getShortcutLabel() + "_w"; std::string str_natoms; Tools::convert( atoms.size(), str_natoms ); 107 0 : readInputLine( getShortcutLabel() + "_w: ONES SIZE=" + str_natoms ); 108 6 : } else if( str_weights.size()==1 && str_weights[0]=="@Masses" ) { 109 0 : wflab = getShortcutLabel() + "_m"; 110 0 : readInputLine( getShortcutLabel() + "_m: MASS ATOMS=" + atlist ); 111 4 : } else if( str_weights.size()>1 ) { 112 6 : std::string vals=str_weights[0]; for(unsigned i=1; i<str_weights.size(); ++i) vals += "," + str_weights[i]; 113 6 : readInputLine( getShortcutLabel() + "_w: CONSTANT VALUES=" + vals ); wflab=getShortcutLabel() + "_w"; 114 : } else { 115 2 : plumed_assert( str_weights.size()==1 ); wflab = getShortcutLabel() + "_cent_w"; 116 2 : ActionWithValue* av=plumed.getActionSet().selectWithLabel<ActionWithValue*>( wflab ); 117 2 : if( !av ) { wflab = str_weights[0]; } 118 : } 119 : // Check for normalisation 120 8 : bool unorm; parseFlag("UNORMALIZED",unorm); 121 : // Find out the type 122 4 : if( getName()!="GYRATION_TENSOR" ) { 123 0 : parse("TYPE",gtype); 124 0 : if( gtype!="RADIUS" && gtype!="TRACE" && gtype!="GTPC_1" && gtype!="GTPC_2" && gtype!="GTPC_3" && gtype!="ASPHERICITY" && gtype!="ACYLINDRICITY" 125 0 : && gtype!= "KAPPA2" && gtype!="RGYR_1" && gtype!="RGYR_2" && gtype!="RGYR_3" ) error("type " + gtype + " is invalid"); 126 : // Check if we need to calculate the unormlised radius 127 0 : if( gtype=="TRACE" || gtype=="KAPPA2" ) unorm=true; 128 : } 129 : // Compute all the vectors separating all the positions from the center 130 4 : std::string distance_act = getShortcutLabel() + "_dists: DISTANCE COMPONENTS" + pbcstr; 131 28 : for(unsigned i=0; i<atoms.size(); ++i) { std::string num; Tools::convert( i+1, num ); distance_act += " ATOMS" + num + "=" + getShortcutLabel() + "_cent," + atoms[i]; } 132 4 : readInputLine( distance_act ); 133 : // And calculate the covariance 134 4 : std::string norm_str; if( unorm ) norm_str = " UNORMALIZED"; 135 4 : if( getName()=="GYRATION_TENSOR" ) { 136 8 : readInputLine( getShortcutLabel() + ": COVARIANCE_MATRIX ARG=" + getShortcutLabel() + "_dists.x," + getShortcutLabel() + "_dists.y," + getShortcutLabel() + "_dists.z WEIGHTS=" + wflab + norm_str ); 137 : return; 138 : } 139 0 : readInputLine( getShortcutLabel() + "_tensor: COVARIANCE_MATRIX ARG=" + getShortcutLabel() + "_dists.x," + getShortcutLabel() + "_dists.y," + getShortcutLabel() + "_dists.z WEIGHTS=" + wflab + norm_str ); 140 : // Pick out the diagonal elements 141 0 : readInputLine( getShortcutLabel() + "_diag_elements: SELECT_COMPONENTS ARG=" + getShortcutLabel() + "_tensor COMPONENTS=1.1,2.2,3.3"); 142 0 : if( gtype=="RADIUS") { 143 : // And now we need the average trace for the gyration radius 144 0 : readInputLine( getShortcutLabel() + "_trace: SUM ARG=" + getShortcutLabel() + "_diag_elements PERIODIC=NO"); 145 : // Square root the radius 146 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_trace FUNC=sqrt(x) PERIODIC=NO"); 147 0 : } else if( gtype=="TRACE" ) { 148 : // Compte the trace of the gyration tensor 149 0 : readInputLine( getShortcutLabel() + "_trace: SUM ARG=" + getShortcutLabel() + "_diag_elements PERIODIC=NO"); 150 : // And double it 151 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_trace FUNC=2*x PERIODIC=NO"); 152 : } else { 153 : // Diagonalize the gyration tensor 154 0 : readInputLine( getShortcutLabel() + "_diag: DIAGONALIZE ARG=" + getShortcutLabel() + "_tensor VECTORS=all" ); 155 0 : if( gtype.find("GTPC")!=std::string::npos ) { 156 0 : std::size_t und=gtype.find_first_of("_"); if( und==std::string::npos ) error( gtype + " is not a valid type for gyration radius"); 157 0 : std::string num = gtype.substr(und+1); if( num!="1" && num!="2" && num!="3" ) error( gtype + " is not a valid type for gyration radius"); 158 : // Now get the appropriate eigenvalue 159 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-" + num + " FUNC=sqrt(x) PERIODIC=NO"); 160 0 : } else if( gtype.find("RGYR")!=std::string::npos ) { 161 0 : std::size_t und=gtype.find_first_of("_"); if( und==std::string::npos ) error( gtype + " is not a valid type for gyration radius"); 162 0 : unsigned ind; Tools::convert( gtype.substr(und+1), ind ); 163 : // Now get the appropriate quantity 164 0 : if( ind==3 ) { 165 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2 FUNC=sqrt(x+y) PERIODIC=NO"); 166 0 : } else if( ind==2 ) { 167 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x+y) PERIODIC=NO"); 168 0 : } else if( ind==1 ) { 169 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x+y) PERIODIC=NO"); 170 0 : } else error( gtype + " is not a valid type for gyration radius"); 171 0 : } else if( gtype=="ASPHERICITY" ) { 172 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x-0.5*(y+z)) PERIODIC=NO" ); 173 0 : } else if( gtype=="ACYLINDRICITY" ) { 174 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=sqrt(x-y) PERIODIC=NO" ); 175 0 : } else if( gtype=="KAPPA2" ) { 176 0 : readInputLine( getShortcutLabel() + "_numer: CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=x*y+x*z+y*z PERIODIC=NO" ); 177 0 : readInputLine( getShortcutLabel() + "_denom: CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + "_diag.vals-2," + getShortcutLabel() + "_diag.vals-3 FUNC=x+y+z PERIODIC=NO" ); 178 0 : readInputLine( getShortcutLabel() + ": CUSTOM ARG=" + getShortcutLabel() + "_numer," + getShortcutLabel() + "_denom FUNC=1-3*(x/(y*y)) PERIODIC=NO"); 179 0 : } else error( gtype + " is not a valid type for gyration radius"); 180 : } 181 124 : } 182 : 183 : } 184 : }