Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) crystdistrib 2023-2023 The code team
3 : (see the PEOPLE-crystdistrib file at the root of this folder for a list of names)
4 :
5 : This file is part of crystdistrib code module.
6 :
7 : The crystdistrib code module is free software: you can redistribute it and/or modify
8 : it under the terms of the GNU Lesser General Public License as published by
9 : the Free Software Foundation, either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : The crystdistrib code module is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public License
18 : along with the crystdistrib code module. If not, see <http://www.gnu.org/licenses/>.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #include "core/ActionShortcut.h"
21 : #include "core/ActionRegister.h"
22 : #include "core/PlumedMain.h"
23 : #include "core/ActionSet.h"
24 : #include "core/ActionWithValue.h"
25 : #include "tools/IFile.h"
26 :
27 : namespace PLMD {
28 : namespace crystdistrib {
29 :
30 : //+PLUMEDOC COLVAR BOPS
31 : /*
32 : Calculate Bond orientational order parameters for molecules.
33 :
34 : BOPS is a shortcut to calculate the Bond-orientational Order Parameters detailed that are described in the paper cited below.
35 : As arguments, BOPS takes a list of atoms (corresponding to molecules), a vector of quaternions, a cutoff distance, and two kernel files
36 : detailing the means, variances, and normalization factors of probability distributions. BOPS returns a vector of order parameters.
37 :
38 : The DOPS kernel file has FIELDS height, mu, and sigma corresponding to the normalization factor, mean, and variance of the gaussian distributions used in the order parameters.
39 : The SET kerneltype is gaussian.
40 :
41 : The BOPS kernel file has FIELDS height, kappa, mu\_i, mu\_j, and mu\_k, which correspond to the normalization factor, reciprocal variance, and imaginary components of the
42 : mean quaternion frame of the fisher distribution used in the order parameters. The SET kerneltype is gaussian.
43 :
44 : BOPS returns one order parameter per atom given, evaluated over each atom's neighbors within the cutoff given. The distribution defined by the kernel files, analogous to a radial distribution function, is defined over all possible unit vectors which could be drawn between two atoms. The order parameter is obtained by evaluating the distribution at each unit vector pointing to all neighbors within the cutoff, and summing them up.
45 :
46 :
47 : This example file calculates the BOPS for a system of 3 molecules.
48 :
49 : ```plumed
50 : #SETTINGS INPUTFILES=regtest/crystdistrib/rt-bops-shortcut/kernels.dat,regtest/crystdistrib/rt-bops-shortcut/kernels2.dat
51 : quat: QUATERNION ATOMS1=1,2,3 ATOMS2=4,5,6 ATOMS3=7,8,9
52 : bops: BOPS SPECIES=1,4,7 QUATERNIONS=quat CUTOFF=100.0 KERNELFILE_DOPS=regtest/crystdistrib/rt-bops-shortcut/kernels.dat KERNELFILE_BOPS=regtest/crystdistrib/rt-bops-shortcut/kernels2.dat
53 : ```
54 :
55 : */
56 : //+ENDPLUMEDOC
57 :
58 : class BopsShortcut : public ActionShortcut {
59 : public:
60 : static void registerKeywords( Keywords& keys );
61 : explicit BopsShortcut(const ActionOptions&);
62 : };
63 :
64 : PLUMED_REGISTER_ACTION(BopsShortcut,"BOPS")
65 :
66 3 : void BopsShortcut::registerKeywords( Keywords& keys ) {
67 3 : ActionShortcut::registerKeywords( keys );
68 3 : keys.add("atoms","SPECIES","this keyword is used for colvars such as coordination number. In that context it specifies that plumed should calculate "
69 : "one coordination number for each of the atoms specified. Each of these coordination numbers specifies how many of the "
70 : "other specified atoms are within a certain cutoff of the central atom. You can specify the atoms here as another multicolvar "
71 : "action or using a MultiColvarFilter or ActionVolume action. When you do so the quantity is calculated for those atoms specified "
72 : "in the previous multicolvar. This is useful if you would like to calculate the Steinhardt parameter for those atoms that have a "
73 : "coordination number more than four for example");
74 3 : keys.add("atoms-2","SPECIESA","this keyword is used for colvars such as the coordination number. In that context it species that plumed should calculate "
75 : "one coordination number for each of the atoms specified in SPECIESA. Each of these cooordination numbers specifies how many "
76 : "of the atoms specifies using SPECIESB is within the specified cutoff. As with the species keyword the input can also be specified "
77 : "using the label of another multicolvar");
78 3 : keys.add("atoms-2","SPECIESB","this keyword is used for colvars such as the coordination number. It must appear with SPECIESA. For a full explanation see "
79 : "the documentation for that keyword");
80 3 : keys.add("compulsory","QUATERNIONS","the label of the action that computes the quaternions that should be used");
81 3 : keys.add("compulsory","KERNELFILE_DOPS","the file containing the list of kernel parameters. We expect h, mu and sigma parameters for a 1D Gaussian kernel of the form h*exp(-(x-mu)^2/2sigma^2)");
82 3 : keys.add("compulsory","KERNELFILE_BOPS","the second file containing the list of kernel parameters. Expecting a normalization factor (height), concentration parameter (kappa), and 3 norm vector pieces of the mean (mu_i, mu_j, mu_k )for a fisher distribution. of the form h*exp(kappa*dot(r_mean,r)), where dot is a standard dot product.");
83 3 : keys.add("compulsory", "CUTOFF", "cutoff for the distance matrix");
84 : // keys.add("compulsory","SWITCH","the switching function that acts on the distances between points)");
85 6 : keys.setValueDescription("vector","the values of the bops order parameters");
86 3 : keys.needsAction("DISTANCE_MATRIX");
87 3 : keys.needsAction("QUATERNION_BOND_PRODUCT_MATRIX");
88 3 : keys.needsAction("CUSTOM");
89 3 : keys.needsAction("ONES");
90 3 : keys.needsAction("MATRIX_VECTOR_PRODUCT");
91 3 : keys.addDOI("10.1063/1.3548889");
92 3 : }
93 :
94 1 : BopsShortcut::BopsShortcut(const ActionOptions&ao):
95 : Action(ao),
96 1 : ActionShortcut(ao) {
97 : // Open a file and read in the kernels
98 : double h_dops,h_bops;
99 : std::string kfunc, kfunc_dops,kfunc_bops,fname_dops,fname_bops;
100 1 : parse("KERNELFILE_DOPS",fname_dops);
101 1 : parse("KERNELFILE_BOPS",fname_bops);
102 1 : IFile ifile_dops, ifile_bops;
103 1 : ifile_dops.open(fname_dops);
104 1 : ifile_bops.open(fname_bops);
105 10 : for(unsigned k=0;; ++k) {
106 21 : if( !ifile_dops.scanField("height",h_dops) || !ifile_bops.scanField("height",h_bops) ) {
107 : break; //checks eof
108 : }
109 : std::string ktype_dops, ktype_bops;
110 10 : ifile_dops.scanField("kerneltype",ktype_dops);
111 20 : ifile_bops.scanField("kerneltype",ktype_bops);
112 10 : if( ktype_dops!="gaussian" ) {
113 0 : error("cannot process kernels of type " + ktype_dops ); //straightup error
114 : }
115 10 : if( ktype_bops!="gaussian" ) {
116 0 : error("cannot process kernels of type " + ktype_bops );
117 : }
118 :
119 : double mu_dops, mu_i, mu_j, mu_k;
120 : std::string hstr_dops, hstr_bops, smu_dops,smu_i, smu_j, smu_k, sigmastr,kappastr;
121 :
122 :
123 10 : Tools::convert( h_dops, hstr_dops );
124 10 : Tools::convert( h_bops, hstr_bops );
125 :
126 10 : ifile_dops.scanField("mu",mu_dops);
127 10 : Tools::convert( mu_dops, smu_dops );
128 : //ifile_bops.scanField("mu_w",mu_w); Tools::convert( mu_w, smu_w );
129 10 : ifile_bops.scanField("mu_i",mu_i);
130 10 : Tools::convert( mu_i, smu_i );
131 10 : ifile_bops.scanField("mu_j",mu_j);
132 10 : Tools::convert( mu_j, smu_j );
133 10 : ifile_bops.scanField("mu_k",mu_k);
134 10 : Tools::convert( mu_k, smu_k );
135 :
136 :
137 : double sigma,kappa;
138 10 : ifile_dops.scanField("sigma",sigma);
139 10 : Tools::convert( sigma, sigmastr );
140 10 : ifile_bops.scanField("kappa",kappa);
141 10 : Tools::convert( kappa, kappastr );
142 :
143 :
144 :
145 10 : ifile_dops.scanField(); /*if( k==0 )*/ kfunc_dops = hstr_dops; //else kfunc_dops += "+" + hstr;
146 10 : ifile_bops.scanField(); /*if( k==0 )*/ kfunc_bops = hstr_bops; //else kfunc_bops += "+" + hstr;
147 :
148 20 : kfunc_bops += "*exp(" + kappastr + "*(i*" + smu_i + "+j*" + smu_j + "+k*" + smu_k + "))";
149 20 : kfunc_dops += "*exp(-(x-" + smu_dops +")^2/" + "(2*" + sigmastr +"*" +sigmastr + "))";
150 10 : if (k==0) {
151 2 : kfunc = kfunc_dops + "*" + kfunc_bops;
152 : } else {
153 18 : kfunc+= "+" + kfunc_dops + "*" + kfunc_bops;
154 : }
155 10 : }
156 : std::string sp_str, specA, specB, grpinfo;
157 : double cutoff;
158 1 : parse("SPECIES",sp_str);
159 1 : parse("SPECIESA",specA);
160 1 : parse("SPECIESB",specB);
161 2 : parse("CUTOFF",cutoff);
162 1 : if( sp_str.length()>0 ) {
163 2 : grpinfo="GROUP=" + sp_str;
164 : } else {//not sure how to use this
165 0 : if( specA.length()==0 || specB.length()==0 ) {
166 0 : error("no atoms were specified in input use either SPECIES or SPECIESA + SPECIESB");
167 : }
168 0 : grpinfo="GROUPA=" + specA + " GROUPB=" + specB;
169 : }
170 : std::string cutstr;
171 1 : Tools::convert( cutoff, cutstr );
172 : // Setup the contact matrix
173 : // std::string switchstr; parse("SWITCH",switchstr);
174 2 : readInputLine( getShortcutLabel() + "_cmat: DISTANCE_MATRIX " + grpinfo + " CUTOFF=" + cutstr + " COMPONENTS");
175 :
176 1 : if( specA.length()==0 ) {
177 : std::string quatstr;
178 1 : parse("QUATERNIONS",quatstr);
179 2 : readInputLine( getShortcutLabel() + "_quatprod: QUATERNION_BOND_PRODUCT_MATRIX ARG=" + quatstr + ".*," + getShortcutLabel() + "_cmat.*" );
180 : } else {
181 0 : plumed_error();
182 : }
183 : //
184 :
185 : ///////////////////
186 : ///replace/////
187 2 : readInputLine( getShortcutLabel() + "_dist: CUSTOM ARG=" + getShortcutLabel() + "_cmat.x," + getShortcutLabel() + "_cmat.y," + getShortcutLabel() + "_cmat.z " +
188 : "FUNC=sqrt((x^2)+(y^2)+(z^2)) PERIODIC=NO");
189 2 : readInputLine( getShortcutLabel() + "_kfunc: CUSTOM ARG=" + getShortcutLabel() + "_quatprod.i," + getShortcutLabel() + "_quatprod.j," + getShortcutLabel() + "_quatprod.k,"+ getShortcutLabel() + "_dist " + "VAR=i,j,k,x FUNC=" + kfunc + " PERIODIC=NO");
190 :
191 : //replace ^^^ to remove distance hack
192 : //readInputLine( getShortcutLabel() + "_kfunc: CUSTOM ARG=" + getShortcutLabel() + "_quatprod.i," + getShortcutLabel() + "_quatprod.j," + getShortcutLabel() + "_quatprod.k,"+ getShortcutLabel() + "_cmat.w " + "VAR=i,j,k,x FUNC=" + kfunc + " PERIODIC=NO");
193 : ///end replace////
194 :
195 : // Element wise product of cmat and kfunc
196 : // readInputLine( getShortcutLabel() + "_kdmat: CUSTOM ARG=" + getShortcutLabel() + "_cmat.w," + getShortcutLabel() + "_kfunc FUNC=x*y PERIODIC=NO");
197 : // Find the number of ones we need to multiply by
198 1 : ActionWithValue* av = plumed.getActionSet().selectWithLabel<ActionWithValue*>( getShortcutLabel() + "_cmat");
199 1 : plumed_assert( av && av->getNumberOfComponents()>0 && (av->copyOutput(0))->getRank()==2 );
200 : std::string size;
201 1 : Tools::convert( (av->copyOutput(0))->getShape()[1], size );
202 2 : readInputLine( getShortcutLabel() + "_ones: ONES SIZE=" + size );
203 : //
204 2 : readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT ARG=" + getShortcutLabel() + "_kfunc," + getShortcutLabel() + "_ones");
205 2 : }
206 :
207 : }
208 : }
209 :
210 :
211 :
|