Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2011-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 "ActionWithVirtualAtom.h" 23 : #include "Atoms.h" 24 : 25 : using namespace std; 26 : 27 : namespace PLMD { 28 : 29 198 : void ActionWithVirtualAtom::registerKeywords(Keywords& keys) { 30 198 : Action::registerKeywords(keys); 31 198 : ActionAtomistic::registerKeywords(keys); 32 792 : keys.add("atoms","ATOMS","the list of atoms which are involved the virtual atom's definition"); 33 198 : } 34 : 35 193 : ActionWithVirtualAtom::ActionWithVirtualAtom(const ActionOptions&ao): 36 : Action(ao), 37 : ActionAtomistic(ao), 38 386 : boxDerivatives(3) 39 : { 40 193 : index=atoms.addVirtualAtom(this); 41 193 : log.printf(" serial associated to this virtual atom is %u\n",index.serial()); 42 193 : } 43 : 44 386 : ActionWithVirtualAtom::~ActionWithVirtualAtom() { 45 193 : atoms.removeVirtualAtom(this); 46 193 : } 47 : 48 7155 : void ActionWithVirtualAtom::apply() { 49 7155 : Vector & f(atoms.forces[index.index()]); 50 115584 : for(unsigned i=0; i<getNumberOfAtoms(); i++) modifyForces()[i]=matmul(derivatives[i],f); 51 7155 : Tensor & v(modifyVirial()); 52 28620 : for(unsigned i=0; i<3; i++) v+=boxDerivatives[i]*f[i]; 53 7155 : f.zero(); // after propagating the force to the atoms used to compute the vatom, we reset this to zero 54 : // this is necessary to avoid double counting if then one tries to compute the total force on the c.o.m. of the system. 55 : // notice that this is currently done in FIT_TO_TEMPLATE 56 7155 : } 57 : 58 182 : void ActionWithVirtualAtom::requestAtoms(const std::vector<AtomNumber> & a) { 59 182 : ActionAtomistic::requestAtoms(a); 60 182 : derivatives.resize(a.size()); 61 182 : } 62 : 63 9 : void ActionWithVirtualAtom::setGradients() { 64 : gradients.clear(); 65 90 : for(unsigned i=0; i<getNumberOfAtoms(); i++) { 66 72 : AtomNumber an=getAbsoluteIndex(i); 67 : // this case if the atom is a virtual one 68 72 : if(atoms.isVirtualAtom(an)) { 69 : const ActionWithVirtualAtom* a=atoms.getVirtualAtomsAction(an); 70 42 : for(const auto & p : a->gradients) { 71 60 : gradients[p.first]+=matmul(derivatives[i],p.second); 72 : } 73 : // this case if the atom is a normal one 74 : } else { 75 60 : gradients[an]+=derivatives[i]; 76 : } 77 : } 78 9 : } 79 : 80 605 : void ActionWithVirtualAtom::setBoxDerivatives(const std::vector<Tensor> &d) { 81 605 : boxDerivatives=d; 82 605 : plumed_assert(d.size()==3); 83 : // Subtract the trivial part coming from a distorsion applied to the ghost atom first. 84 : // Notice that this part alone should exactly cancel the already accumulated virial 85 : // due to forces on this atom. 86 1210 : Vector pos=atoms.positions[index.index()]; 87 6050 : for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) boxDerivatives[j][i][j]+=pos[i]; 88 605 : } 89 : 90 605 : void ActionWithVirtualAtom::setBoxDerivativesNoPbc() { 91 605 : std::vector<Tensor> bd(3); 92 16940 : for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) for(unsigned k=0; k<3; k++) { 93 : // Notice that this expression is very similar to the one used in Colvar::setBoxDerivativesNoPbc(). 94 : // Indeed, we have the negative of a sum over dependent atoms (l) of the external product between positions 95 : // and derivatives. Notice that this only works only when Pbc have not been used to compute 96 : // derivatives. 97 17469 : for(unsigned l=0; l<getNumberOfAtoms(); l++) { 98 2268 : bd[k][i][j]-=getPosition(l)[i]*derivatives[l][j][k]; 99 : } 100 : } 101 605 : setBoxDerivatives(bd); 102 605 : } 103 : 104 : 105 : 106 7239 : void ActionWithVirtualAtom::setGradientsIfNeeded() { 107 14478 : if(isOptionOn("GRADIENTS")) { 108 9 : setGradients() ; 109 : } 110 7239 : } 111 : 112 5874 : }