-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathManyAngle.cpp
216 lines (172 loc) · 6.95 KB
/
ManyAngle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 2011-2016 The plumed team
(see the PEOPLE file at the root of the distribution for a list of names)
See http://www.plumed.org for more information.
This file is part of plumed, version 2.
plumed is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
plumed is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with plumed. If not, see <http://www.gnu.org/licenses/>.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
#include "colvar/Colvar.h"
#include "colvar/ActionRegister.h"
#include "tools/Communicator.h"
#include "tools/Tools.h"
#include "tools/Angle.h"
#include "tools/IFile.h"
#include <string>
#include <math.h>
using namespace std;
namespace PLMD{
namespace colvar{
//+PLUMEDOC COLVAR MANY_ANGLE
/*
\plumedfile
LOAD FILE=ManyAngle.cpp
# Define groups for the CV
INCLUDE FILE=centers.dat
C: GROUP ATOMS=1-864:8
O: GROUP ATOMS=2-864:8
N1: GROUP ATOMS=3-864:8
N2: GROUP ATOMS=6-864:8
MANY_ANGLE ...
LABEL=ma
CENTER=C
START=N1
END=N2
RCUT=0.7
UP_DOWN_SYMMETRY
... MANY_ANGLE
PRINT STRIDE=1 ARG=* FILE=COLVAR_MA
\endplumedfile
*/
//+ENDPLUMEDOC
class ManyAngle : public Colvar {
bool pbc, serial;
vector<AtomNumber> center_lista, start_lista, end_lista;
std::vector<PLMD::AtomNumber> atomsToRequest;
double rcut, rcut2;
public:
explicit ManyAngle(const ActionOptions&);
virtual void calculate();
static void registerKeywords( Keywords& keys );
};
PLUMED_REGISTER_ACTION(ManyAngle,"MANY_ANGLE")
void ManyAngle::registerKeywords( Keywords& keys ){
Colvar::registerKeywords(keys);
keys.addFlag("SERIAL",false,"Perform the calculation in serial - for debug purpose");
keys.add("atoms","CENTER","Center atoms");
keys.add("atoms","START","Start point of vector defining orientation");
keys.add("atoms","END","End point of vector defining orientation");
keys.add("compulsory","RCUT","1","Maximum distance for being neighbor");
}
ManyAngle::ManyAngle(const ActionOptions&ao):
PLUMED_COLVAR_INIT(ao),
pbc(true),
serial(false)
{
parseFlag("SERIAL",serial);
parseAtomList("CENTER",center_lista);
parseAtomList("START",start_lista);
parseAtomList("END",end_lista);
if(center_lista.size()!=start_lista.size()) error("Number of atoms in START must be equal to the number of atoms in CENTER");
if(center_lista.size()!=end_lista.size()) error("Number of atoms in END must be equal to the number of atoms in CENTER");
bool nopbc=!pbc;
parseFlag("NOPBC",nopbc);
pbc=!nopbc;
if(pbc) log.printf(" using periodic boundary conditions\n");
else log.printf(" without periodic boundary conditions\n");
addValueWithDerivatives(); setNotPeriodic();
parse("RCUT",rcut);
log.printf(" The neighbor is defined within 0 and %f \n", rcut);
rcut2 = rcut*rcut;
checkRead();
atomsToRequest.reserve ( center_lista.size() + start_lista.size() + end_lista.size() );
atomsToRequest.insert (atomsToRequest.end(), center_lista.begin(), center_lista.end() );
atomsToRequest.insert (atomsToRequest.end(), start_lista.begin(), start_lista.end() );
atomsToRequest.insert (atomsToRequest.end(), end_lista.begin(), end_lista.end() );
requestAtoms(atomsToRequest);
}
// calculator
void ManyAngle::calculate()
{
double cv=0.0; // (T)
unsigned nat=getNumberOfAtoms();
vector<Vector> deriv(nat); // This will initialized vector with 0 modulo. (T)
unsigned int num_cv=0; // (T)
double angle(0.0); // (T)
double xi(0.0); // (T)
double pa(0.0); // (T)
double dcv_dangle(0.0); // (T)
if(pbc) makeWhole();
// Setup parallelization
unsigned stride=comm.Get_size();
unsigned rank=comm.Get_rank();
if(serial){
stride=1;
rank=0;
} else {
stride=comm.Get_size();
rank=comm.Get_rank();
}
for(unsigned int i=rank;i<(center_lista.size()-1);i+=stride) {
unsigned atom1_mol1=i+center_lista.size();
unsigned atom2_mol1=i+center_lista.size()+start_lista.size();
Vector dik=pbcDistance(getPosition(atom2_mol1),getPosition(atom1_mol1));
for(unsigned int j=i+1;j<center_lista.size();j+=1) {
if(getAbsoluteIndex(i)==getAbsoluteIndex(j)) continue;
Vector distance;
if(pbc){
distance=pbcDistance(getPosition(i),getPosition(j));
} else {
distance=delta(getPosition(i),getPosition(j));
}
double d2=0.0; // (T)
if ( (d2=distance[0]*distance[0])<rcut2 && (d2+=distance[1]*distance[1])<rcut2 && (d2+=distance[2]*distance[2])<rcut2) {
unsigned atom1_mol2=j+center_lista.size();
unsigned atom2_mol2=j+center_lista.size()+start_lista.size();
Vector dij=pbcDistance(getPosition(atom1_mol2),getPosition(atom2_mol2));
Vector ddij,ddik; // (T)
PLMD::Angle a; // (T)
angle=a.compute(dij,dik,ddij,ddik); // (T)
xi=tanh(20.0*(angle-1.85)); // (T)
pa=pi-2.0*angle; // (T)
cv += 0.5*(pa*xi + pi); // (T)
dcv_dangle=10.0*pa*(1.0-xi*xi)-xi; // (T)
// Chain rule. d(cv)/d(angle)*d(angle)/d(dik)
deriv[atom1_mol1]+=dcv_dangle*ddik; // (T)
deriv[atom2_mol1]+=-dcv_dangle*ddik; // (T)
deriv[atom1_mol2]+=-dcv_dangle*ddij; // (T)
deriv[atom2_mol2]+=dcv_dangle*ddij; // (T)
num_cv++; // (T)
}
}
}
if(!serial){
comm.Sum(cv);
comm.Sum(num_cv);
comm.Sum(deriv);
}
// Assign output quantities
Tensor virial; // (T)
for(unsigned i=0;i<nat;++i){
// If atom 3 is involved in calculation of 2 angles when there are 3 angles being actually calculated,
// This derivatives of atom 3 will be the sum of derivatives of atom 3 calculated in each angle divided
// by 3 (angles).
setAtomsDerivatives(i, deriv[i]/num_cv); // (T)
// This line is calculated in the same way as what has been defined in Colvar::setBoxDerivativesNoPbc(Value* v).
virial-=Tensor(getPosition(i), deriv[i]/num_cv); // (T)
}
setValue( cv/num_cv ); // (T)
// If double dcv_dangle, the box derivatives will double. When there are [num_cv] angles being calculated,
// the box derivatives will be the sum of box derivatives of each individual angles.
setBoxDerivatives(virial); // (T)
}
}
}