1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2011-2021 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 "CoordinationBase.h"
23 #include "tools/SwitchingFunction.h"
24 #include "ActionRegister.h"
25 
26 #include <string>
27 
28 using namespace std;
29 
30 namespace PLMD {
31 namespace colvar {
32 
33 //+PLUMEDOC COLVAR COORDINATION
34 /*
35 Calculate coordination numbers.
36 
37 This keyword can be used to calculate the number of contacts between two groups of atoms
38 and is defined as
39 \f[
40 \sum_{i\in A} \sum_{i\in B} s_{ij}
41 \f]
42 where \f$s_{ij}\f$ is 1 if the contact between atoms \f$i\f$ and \f$j\f$ is formed,
43 zero otherwise.
44 In actuality, \f$s_{ij}\f$ is replaced with a switching function so as to ensure that the calculated CV has continuous derivatives.
45 The default switching function is:
46 \f[
47 s_{ij} = \frac{ 1 - \left(\frac{{\bf r}_{ij}-d_0}{r_0}\right)^n } { 1 - \left(\frac{{\bf r}_{ij}-d_0}{r_0}\right)^m }
48 \f]
49 but it can be changed using the optional SWITCH option.
50 
51 To make your calculation faster you can use a neighbor list, which makes it that only a
52 relevant subset of the pairwise distance are calculated at every step.
53 
54 If GROUPB is empty, it will sum the \f$\frac{N(N-1)}{2}\f$ pairs in GROUPA. This avoids computing
55 twice permuted indexes (e.g. pair (i,j) and (j,i)) thus running at twice the speed.
56 
57 Notice that if there are common atoms between GROUPA and GROUPB the switching function should be
58 equal to one. These "self contacts" are discarded by plumed (since version 2.1),
59 so that they actually count as "zero".
60 
61 
62 \par Examples
63 
64 The following example instructs plumed to calculate the total coordination number of the atoms in group 1-10 with the atoms in group 20-100.  For atoms 1-10 coordination numbers are calculated that count the number of atoms from the second group that are within 0.3 nm of the central atom.  A neighbor list is used to make this calculation faster, this neighbor list is updated every 100 steps.
65 \plumedfile
66 COORDINATION GROUPA=1-10 GROUPB=20-100 R_0=0.3 NLIST NL_CUTOFF=0.5 NL_STRIDE=100
67 \endplumedfile
68 
69 The following is a dummy example which should compute the value 0 because the self interaction
70 of atom 1 is skipped. Notice that in plumed 2.0 "self interactions" were not skipped, and the
71 same calculation should return 1.
72 \plumedfile
73 c: COORDINATION GROUPA=1 GROUPB=1 R_0=0.3
74 PRINT ARG=c STRIDE=10
75 \endplumedfile
76 
77 Here's an example that shows what happens when providing COORDINATION with
78 a single group:
79 \plumedfile
80 # define some huge group:
81 group: GROUP ATOMS=1-1000
82 # Here's coordination of a group against itself:
83 c1: COORDINATION GROUPA=group GROUPB=group R_0=0.3
84 # Here's coordination within a single group:
85 x: COORDINATION GROUPA=group R_0=0.3
86 # This is just multiplying times 2 the variable x:
87 c2: COMBINE ARG=x COEFFICIENTS=2 PERIODIC=NO
88 
89 # the two variables c1 and c2 should be identical, but the calculation of c2 is twice faster
90 # since it runs on half of the pairs.
91 PRINT ARG=c1,c2 STRIDE=10
92 \endplumedfile
93 
94 
95 
96 */
97 //+ENDPLUMEDOC
98 
99 class Coordination : public CoordinationBase {
100   SwitchingFunction switchingFunction;
101 
102 public:
103   explicit Coordination(const ActionOptions&);
104 // active methods:
105   static void registerKeywords( Keywords& keys );
106   double pairing(double distance,double&dfunc,unsigned i,unsigned j)const override;
107 };
108 
109 PLUMED_REGISTER_ACTION(Coordination,"COORDINATION")
110 
registerKeywords(Keywords & keys)111 void Coordination::registerKeywords( Keywords& keys ) {
112   CoordinationBase::registerKeywords(keys);
113   keys.add("compulsory","NN","6","The n parameter of the switching function ");
114   keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN");
115   keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function");
116   keys.add("compulsory","R_0","The r_0 parameter of the switching function");
117   keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous switching function defined above. "
118            "The following provides information on the \\ref switchingfunction that are available. "
119            "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords.");
120 }
121 
Coordination(const ActionOptions & ao)122 Coordination::Coordination(const ActionOptions&ao):
123   Action(ao),
124   CoordinationBase(ao)
125 {
126 
127   string sw,errors;
128   parse("SWITCH",sw);
129   if(sw.length()>0) {
130     switchingFunction.set(sw,errors);
131     if( errors.length()!=0 ) error("problem reading SWITCH keyword : " + errors );
132   } else {
133     int nn=6;
134     int mm=0;
135     double d0=0.0;
136     double r0=0.0;
137     parse("R_0",r0);
138     if(r0<=0.0) error("R_0 should be explicitly specified and positive");
139     parse("D_0",d0);
140     parse("NN",nn);
141     parse("MM",mm);
142     switchingFunction.set(nn,mm,r0,d0);
143   }
144 
145   checkRead();
146 
147   log<<"  contacts are counted with cutoff "<<switchingFunction.description()<<"\n";
148 }
149 
pairing(double distance,double & dfunc,unsigned i,unsigned j) const150 double Coordination::pairing(double distance,double&dfunc,unsigned i,unsigned j)const {
151   (void) i; // avoid warnings
152   (void) j; // avoid warnings
153   return switchingFunction.calculateSqr(distance,dfunc);
154 }
155 
156 }
157 
158 }
159