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 "ActionRegister.h"
24 : #include "core/PlumedMain.h"
25 : #include "core/Atoms.h"
26 : #include <cmath>
27 :
28 : using namespace std;
29 :
30 : namespace PLMD {
31 : namespace vatom {
32 :
33 : //+PLUMEDOC VATOM COM
34 : /*
35 : Calculate the center of mass for a group of atoms.
36 :
37 : The computed
38 : center of mass is stored as a virtual atom that can be accessed in
39 : an atom list through the label for the COM action that creates it.
40 :
41 : For arbitrary weights (e.g. geometric center) see \ref CENTER.
42 :
43 : When running with periodic boundary conditions, the atoms should be
44 : in the proper periodic image. This is done automatically since PLUMED 2.2,
45 : by considering the ordered list of atoms and rebuilding PBCs with a procedure
46 : that is equivalent to that done in \ref WHOLEMOLECULES . Notice that
47 : rebuilding is local to this action. This is different from \ref WHOLEMOLECULES
48 : which actually modifies the coordinates stored in PLUMED.
49 :
50 : In case you want to recover the old behavior you should use the NOPBC flag.
51 : In that case you need to take care that atoms are in the correct
52 : periodic image.
53 :
54 : \par Examples
55 :
56 : The following input instructs plumed to print the distance between the
57 : center of mass for atoms 1,2,3,4,5,6,7 and that for atoms 15,20:
58 : \plumedfile
59 : c1: COM ATOMS=1-7
60 : c2: COM ATOMS=15,20
61 : d1: DISTANCE ATOMS=c1,c2
62 : PRINT ARG=d1
63 : \endplumedfile
64 :
65 : */
66 : //+ENDPLUMEDOC
67 :
68 :
69 58 : class COM:
70 : public ActionWithVirtualAtom
71 : {
72 : bool nopbc;
73 : bool first;
74 : public:
75 : explicit COM(const ActionOptions&ao);
76 : void calculate();
77 : static void registerKeywords( Keywords& keys );
78 : };
79 :
80 6510 : PLUMED_REGISTER_ACTION(COM,"COM")
81 :
82 59 : void COM::registerKeywords(Keywords& keys) {
83 59 : ActionWithVirtualAtom::registerKeywords(keys);
84 177 : keys.addFlag("NOPBC",false,"ignore the periodic boundary conditions when calculating distances");
85 59 : }
86 :
87 58 : COM::COM(const ActionOptions&ao):
88 : Action(ao),
89 : ActionWithVirtualAtom(ao),
90 : nopbc(false),
91 58 : first(true)
92 : {
93 : vector<AtomNumber> atoms;
94 116 : parseAtomList("ATOMS",atoms);
95 58 : if(atoms.size()==0) error("at least one atom should be specified");
96 116 : parseFlag("NOPBC",nopbc);
97 58 : checkRead();
98 58 : log.printf(" of atoms");
99 2423 : for(unsigned i=0; i<atoms.size(); ++i) {
100 769 : if(i%25==0) log<<"\n";
101 1538 : log.printf(" %d",atoms[i].serial());
102 : }
103 58 : log.printf("\n");
104 58 : if(nopbc) {
105 23 : log<<" PBC will be ignored\n";
106 : } else {
107 35 : log<<" broken molecules will be rebuilt assuming atoms are in the proper order\n";
108 : }
109 58 : requestAtoms(atoms);
110 58 : }
111 :
112 2427 : void COM::calculate() {
113 2427 : Vector pos;
114 2427 : if(!nopbc) makeWhole();
115 : double mass(0.0);
116 2427 : if( first ) {
117 496 : for(unsigned i=0; i<getNumberOfAtoms(); i++) {
118 496 : if(std::isnan(getMass(i))) {
119 0 : error(
120 : "You are trying to compute a COM but masses are not known.\n"
121 : " If you are using plumed driver, please use the --mc option"
122 : );
123 : }
124 : }
125 49 : first=false;
126 : }
127 2427 : vector<Tensor> deriv(getNumberOfAtoms());
128 39153 : for(unsigned i=0; i<getNumberOfAtoms(); i++) mass+=getMass(i);
129 4854 : if( plumed.getAtoms().chargesWereSet() ) {
130 : double charge(0.0);
131 4175 : for(unsigned i=0; i<getNumberOfAtoms(); i++) charge+=getCharge(i);
132 : setCharge(charge);
133 : } else {
134 : setCharge(0.0);
135 : }
136 39153 : for(unsigned i=0; i<getNumberOfAtoms(); i++) {
137 36726 : pos+=(getMass(i)/mass)*getPosition(i);
138 55089 : deriv[i]=(getMass(i)/mass)*Tensor::identity();
139 : }
140 : setPosition(pos);
141 : setMass(mass);
142 : setAtomsDerivatives(deriv);
143 2427 : }
144 :
145 : }
146 4839 : }
|