Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-2017 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 "RDF.h"
23 : #include "core/ActionRegister.h"
24 :
25 : //+PLUMEDOC ANALYSIS RDF
26 : /*
27 : Calculate the radial distribution function
28 :
29 : \par Examples
30 :
31 : */
32 : //+ENDPLUMEDOC
33 :
34 : namespace PLMD {
35 : namespace gridtools {
36 :
37 : PLUMED_REGISTER_ACTION(RDF,"RDF")
38 :
39 3 : void RDF::createX2ReferenceObject( const std::string& lab, const std::string& grid_setup, const bool& calc_dens, ActionShortcut* action ) {
40 : // Create grid with normalizing function
41 6 : action->readInputLine( lab + "_x2: REFERENCE_GRID PERIODIC=NO FUNC=x*x " + grid_setup );
42 : // Compute density if required
43 3 : if( calc_dens ) {
44 6 : action->readInputLine( lab + "_vol: VOLUME" );
45 : }
46 3 : }
47 :
48 267 : void RDF::registerKeywords( Keywords& keys ) {
49 267 : ActionShortcut::registerKeywords( keys );
50 267 : keys.add("atoms","GROUP","the atoms that are being used to calculate the RDF");
51 267 : keys.add("atoms","ATOMS","the atoms that are being used to calculate the RDF");
52 267 : keys.add("atoms-2","GROUPA","the atoms that you would like to compute the RDF about. Must be used with GROUPB.");
53 267 : keys.add("atoms-2","GROUPB","the atoms that you would like to to use when computing the RDF around the atoms that were specified with GROUPA");
54 267 : keys.add("compulsory","GRID_BIN","the number of bins to use when computing the RDF");
55 267 : keys.add("compulsory","KERNEL","GAUSSIAN","the type of kernel to use for computing the histograms for the RDF");
56 267 : keys.add("compulsory","CUTOFF","6.25","the cutoff at which to stop evaluating the kernel functions is set equal to sqrt(2*x)*bandwidth in each direction where x is this number");
57 267 : keys.add("compulsory","MAXR","the maximum distance to use for the rdf");
58 267 : keys.add("compulsory","BANDWIDTH","the bandwidths for kernel density esimtation");
59 267 : keys.add("compulsory","CLEAR","1","the frequency with which to clear the estimate of the rdf. Set equal to 0 if you want to compute an rdf over the whole trajectory");
60 267 : keys.add("compulsory","STRIDE","1","the frequency with which to compute the rdf and accumulate averages");
61 267 : keys.add("optional","DENSITY","the reference density to use when normalizing the RDF");
62 267 : keys.add("hidden","REFERENCE","this is the label of the reference objects");
63 534 : keys.setValueDescription("grid","the radial distribution function");
64 267 : keys.needsAction("REFERENCE_GRID");
65 267 : keys.needsAction("VOLUME");
66 267 : keys.needsAction("DISTANCE_MATRIX");
67 267 : keys.needsAction("CUSTOM");
68 267 : keys.needsAction("KDE");
69 267 : keys.needsAction("ACCUMULATE");
70 267 : keys.needsAction("CONSTANT");
71 267 : }
72 :
73 66 : RDF::RDF(const ActionOptions&ao):
74 : Action(ao),
75 66 : ActionShortcut(ao) {
76 : // Read in grid extent and number of bins
77 : std::string maxr, nbins, dens;
78 66 : parse("MAXR",maxr);
79 66 : parse("GRID_BIN",nbins);
80 66 : parse("DENSITY",dens);
81 132 : std::string grid_setup = "GRID_MIN=0 GRID_MAX=" + maxr + " GRID_BIN=" + nbins;
82 : // Create grid with normalizing function on it
83 : std::string refstr;
84 132 : parse("REFERENCE",refstr);
85 66 : if( refstr.length()==0 ) {
86 2 : createX2ReferenceObject( getShortcutLabel(), grid_setup, dens.length()==0, this );
87 2 : refstr = getShortcutLabel();
88 : }
89 : // Read input to histogram
90 : std::string cutoff, kernel, bandwidth, kernel_data;
91 132 : parse("KERNEL",kernel);
92 66 : if( kernel=="DISCRETE" ) {
93 : cutoff = maxr;
94 : kernel_data="KERNEL=DISCRETE";
95 2 : warning("rdf is normalised by dividing by the surface area at the grid value and not by the volume of the bin as it should be with discrete kernels");
96 : } else {
97 65 : parse("BANDWIDTH",bandwidth);
98 : double rcut;
99 65 : parse("CUTOFF",rcut);
100 130 : kernel_data="KERNEL=" + kernel + " IGNORE_IF_OUT_OF_RANGE BANDWIDTH=" + bandwidth;
101 : double bw;
102 65 : Tools::convert( bandwidth, bw );
103 : double fcut;
104 65 : Tools::convert( maxr, fcut );
105 65 : Tools::convert( fcut + sqrt(2.0*rcut)*bw, cutoff );
106 : }
107 :
108 : // Create contact matrix
109 : std::string natoms, str_norm_atoms, atom_str, group_str, groupa_str, groupb_str;
110 132 : parse("GROUP",group_str);
111 66 : if( group_str.size()==0 ) {
112 128 : parse("ATOMS",group_str);
113 : }
114 66 : if( group_str.length()>0 ) {
115 2 : atom_str="GROUP=" + group_str;
116 2 : std::vector<std::string> awords=Tools::getWords(group_str,"\t\n ,");
117 2 : Tools::interpretRanges( awords );
118 2 : Tools::convert( awords.size(), natoms );
119 : str_norm_atoms = natoms;
120 2 : } else {
121 64 : parse("GROUPA",groupa_str);
122 64 : parse("GROUPB",groupb_str);
123 64 : std::vector<std::string> awords=Tools::getWords(groupb_str,"\t\n ,");
124 64 : Tools::interpretRanges( awords );
125 64 : Tools::convert( awords.size(), natoms );
126 128 : atom_str="GROUPA=" + groupa_str + " GROUPB=" + groupb_str;
127 64 : std::vector<std::string> bwords=Tools::getWords(groupa_str,"\t\n ,");
128 64 : Tools::interpretRanges( bwords );
129 64 : Tools::convert( bwords.size()+1, str_norm_atoms );
130 64 : }
131 : // Retrieve the number of atoms
132 132 : readInputLine( getShortcutLabel() + "_mat: DISTANCE_MATRIX CUTOFF=" + cutoff + " " + atom_str);
133 :
134 : // Calculate weights of distances
135 132 : readInputLine( getShortcutLabel() + "_wmat: CUSTOM ARG=" + getShortcutLabel() + "_mat FUNC=step(" + cutoff + "-x) PERIODIC=NO");
136 : // Now create a histogram from the contact matrix
137 : unsigned clear, stride;
138 66 : parse("CLEAR",clear);
139 66 : parse("STRIDE",stride);
140 66 : if( clear==1 ) {
141 130 : readInputLine( getShortcutLabel() + "_kde: KDE ARG=" + getShortcutLabel() + "_mat VOLUMES=" + getShortcutLabel() + "_wmat " + grid_setup + " " + kernel_data);
142 : } else {
143 : std::string stridestr, clearstr;
144 1 : Tools::convert( stride, stridestr );
145 1 : Tools::convert( clear, clearstr );
146 2 : readInputLine( getShortcutLabel() + "_okde: KDE ARG=" + getShortcutLabel() + "_mat HEIGHTS=" + getShortcutLabel() + "_wmat " + grid_setup + " " + kernel_data);
147 2 : readInputLine( getShortcutLabel() + "_kde: ACCUMULATE ARG=" + getShortcutLabel() + "_okde STRIDE=" + stridestr + " CLEAR=" + clearstr );
148 1 : readInputLine( getShortcutLabel() + "_one: CONSTANT VALUE=1");
149 2 : readInputLine( getShortcutLabel() + "_norm: ACCUMULATE ARG=" + getShortcutLabel() + "_one STRIDE=" + stridestr + " CLEAR=" + clearstr );
150 : }
151 : // Transform the histogram by normalizing factor for rdf
152 132 : readInputLine( getShortcutLabel() + "_vrdf: CUSTOM ARG=" + getShortcutLabel() + "_kde," + refstr + "_x2 FUNC=x/(4*pi*y) PERIODIC=NO");
153 : // And normalize by density and number of atoms (separated from above to avoid nans)
154 132 : std::string func_str = "PERIODIC=NO ARG=" + getShortcutLabel() + "_vrdf";
155 66 : if( dens.length()>0 ) {
156 0 : if( clear==1 ) {
157 0 : func_str += " FUNC=x/(" + dens + "*" + str_norm_atoms + ")";
158 : } else {
159 0 : func_str += "," + getShortcutLabel() + "_norm FUNC=x/(y*" + dens + "*" + str_norm_atoms + ")";
160 : }
161 : } else {
162 66 : if( clear==1 ) {
163 130 : func_str += "," + refstr + "_vol FUNC=x*y/(" + natoms + "*" + str_norm_atoms + ")";
164 : } else {
165 2 : func_str += "," + refstr + "_vol," + getShortcutLabel() + "_norm FUNC=x*y/(z*" + natoms + "*" + str_norm_atoms + ")";
166 : }
167 : }
168 132 : readInputLine( getShortcutLabel() + ": CUSTOM " + func_str);
169 66 : }
170 :
171 : }
172 : }
|