Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2015-2023 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 "ActionWithVirtualAtom.h" 23 : #include "core/ActionRegister.h" 24 : #include "tools/Vector.h" 25 : #include "tools/Exception.h" 26 : 27 : namespace PLMD { 28 : namespace vatom { 29 : 30 : //+PLUMEDOC VATOM FIXEDATOM 31 : /* 32 : Add a virtual atom in a fixed position. 33 : 34 : This action creates [a virtual atom](specifying_atoms.md) at a fixed position. The example input below illustrates 35 : how this idea can be used to compute the angle between the vector connecting atoms 15 and 20 and the z axis and how this 36 : quantity can then be restrained so that the angle stays close to zero. 37 : 38 : ```plumed 39 : a: FIXEDATOM AT=0,0,0 40 : b: FIXEDATOM AT=0,0,1 41 : an: ANGLE ATOMS=a,b,15,20 42 : RESTRAINT ARG=an AT=0.0 KAPPA=100.0 43 : ``` 44 : 45 : By default PLUMED assumes that any coordinates specified using the AT keyword specified are the cartesian coordinates of the fixed atom. 46 : However, if you use the SCALED_COMPONENTS flag as shown below: 47 : 48 : ```plumed 49 : a: FIXEDATOM AT=0.25,0.25,0.25 SCALED_COMPONENTS 50 : DUMPATOMS ATOMS=a FILE=vatom.xyz 51 : ``` 52 : 53 : the coordinates specified using the AT keyword are interpreted as scaled coordinates. The positions output to the `vatom.xyz` file 54 : in the input above is thus obtained by multiplying the input vector by the cell vectors on every step. The position of the atom `a` 55 : thus changes as the box size changes. 56 : 57 : It is also possible to assign a predefined charge or mass to the atom by using the `SET_MASS` and `SET_CHARGE` keywords. 58 : 59 : !!! caution "" 60 : 61 : This action, like [POSITION](POSITION.md) is not invariant for translation of the system so adding a force on it can cause trouble. 62 : 63 : The problem is that the vector connecting any atom and a virtual atom created using the FIXEDATOM atoms command is not invariant to translation. 64 : However, if, as has been done in the following example input, one first aligns atoms to a reference using [FIT_TO_TEMPLATE](FIT_TO_TEMPLATE.md), 65 : then it is safe to add further fixed atoms without breaking translational invariance. 66 : 67 : ```plumed 68 : #SETTINGS INPUTFILES=regtest/basic/rt63/align.pdb 69 : FIT_TO_TEMPLATE STRIDE=1 REFERENCE=regtest/basic/rt63/align.pdb TYPE=SIMPLE 70 : a: FIXEDATOM AT=10,20,30 71 : d: DISTANCE ATOMS=a,20 72 : PRINT ARG=d FILE=colvar 73 : ``` 74 : 75 : */ 76 : //+ENDPLUMEDOC 77 : 78 : 79 : class FixedAtom: 80 : public ActionWithVirtualAtom { 81 : Vector coord; 82 : std::vector<Tensor> deriv; 83 : double mass,charge; 84 : bool scaled_components; 85 : bool warnedNoBox=false; 86 : public: 87 : explicit FixedAtom(const ActionOptions&ao); 88 : void calculate() override; 89 : static void registerKeywords( Keywords& keys ); 90 : }; 91 : 92 : PLUMED_REGISTER_ACTION(FixedAtom,"FIXEDATOM") 93 : 94 49 : void FixedAtom::registerKeywords(Keywords& keys) { 95 49 : ActionWithVirtualAtom::registerKeywords(keys); 96 49 : keys.add("compulsory","AT","coordinates of the virtual atom"); 97 49 : keys.add("compulsory","SET_MASS","1","mass of the virtual atom"); 98 49 : keys.add("compulsory","SET_CHARGE","0","charge of the virtual atom"); 99 49 : keys.addFlag("SCALED_COMPONENTS",false,"use scaled components"); 100 98 : keys.reset_style("ATOMS","hidden"); 101 49 : } 102 : 103 42 : FixedAtom::FixedAtom(const ActionOptions&ao): 104 : Action(ao), 105 42 : ActionWithVirtualAtom(ao) { 106 42 : std::vector<AtomNumber> atoms; 107 84 : parseAtomList("ATOMS",atoms); 108 42 : if(atoms.size()!=0) { 109 0 : error("ATOMS should be empty"); 110 : } 111 : 112 42 : parseFlag("SCALED_COMPONENTS",scaled_components); 113 : 114 42 : std::vector<double> at; 115 84 : parseVector("AT",at); 116 42 : if(at.size()!=3) { 117 0 : error("AT should be a list of three real numbers"); 118 : } 119 : 120 42 : parse("SET_MASS",mass); 121 84 : parse("SET_CHARGE",charge); 122 : 123 42 : coord[0]=at[0]; 124 42 : coord[1]=at[1]; 125 42 : coord[2]=at[2]; 126 : 127 42 : checkRead(); 128 42 : log<<" AT position "<<coord[0]<<" "<<coord[1]<<" "<<coord[2]<<"\n"; 129 42 : if(scaled_components) { 130 1 : log<<" position is in scaled components\n"; 131 : } 132 42 : } 133 : 134 792 : void FixedAtom::calculate() { 135 792 : deriv.resize(getNumberOfAtoms()); 136 792 : if(scaled_components) { 137 : // without a cell the scaled components cannot be converted: the atom ends up in the origin 138 5 : if(!getPbc().isSet() && !warnedNoBox) { 139 1 : warning("SCALED_COMPONENTS was used but the cell is not set: the position of the atom is set to the origin"); 140 1 : warnedNoBox=true; 141 : } 142 5 : setPosition(getPbc().scaledToReal(coord)); 143 : } else { 144 787 : setPosition(coord); 145 : } 146 792 : setMass(mass); 147 792 : setCharge(charge); 148 792 : setAtomsDerivatives(deriv); 149 : // Virial contribution 150 792 : if(!scaled_components) { 151 787 : setBoxDerivativesNoPbc(); 152 : } 153 : // notice that with scaled components there is no additional virial contribution 154 792 : } 155 : 156 : } 157 : }