00001 #include <cmath>
00002
00003 #include "colvarmodule.h"
00004 #include "colvarparse.h"
00005 #include "colvaratoms.h"
00006 #include "colvarvalue.h"
00007 #include "colvar.h"
00008 #include "colvarcomp.h"
00009
00010
00011
00012 template<bool calculate_gradients>
00013 cvm::real colvar::coordnum::switching_function (cvm::real const &r0,
00014 int const &en,
00015 int const &ed,
00016 cvm::atom &A1,
00017 cvm::atom &A2)
00018 {
00019 cvm::rvector const diff = cvm::position_distance (A1.pos, A2.pos);
00020 cvm::real const l2 = diff.norm2()/(r0*r0);
00021
00022
00023 int const en2 = en/2;
00024 int const ed2 = ed/2;
00025
00026 cvm::real const xn = ::pow (l2, en2);
00027 cvm::real const xd = ::pow (l2, ed2);
00028 cvm::real const func = (1.0-xn)/(1.0-xd);
00029
00030 if (calculate_gradients) {
00031 cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0);
00032 cvm::rvector const dl2dx = (2.0/(r0*r0))*diff;
00033 A1.grad += (-1.0)*dFdl2*dl2dx;
00034 A2.grad += dFdl2*dl2dx;
00035 }
00036
00037 return func;
00038 }
00039
00040
00041 template<bool calculate_gradients>
00042 cvm::real colvar::coordnum::switching_function (cvm::rvector const &r0_vec,
00043 int const &en,
00044 int const &ed,
00045 cvm::atom &A1,
00046 cvm::atom &A2)
00047 {
00048 cvm::rvector const diff = cvm::position_distance (A1.pos, A2.pos);
00049 cvm::rvector const scal_diff (diff.x/r0_vec.x, diff.y/r0_vec.y, diff.z/r0_vec.z);
00050 cvm::real const l2 = scal_diff.norm2();
00051
00052
00053 int const en2 = en/2;
00054 int const ed2 = ed/2;
00055
00056 cvm::real const xn = ::pow (l2, en2);
00057 cvm::real const xd = ::pow (l2, ed2);
00058 cvm::real const func = (1.0-xn)/(1.0-xd);
00059
00060 if (calculate_gradients) {
00061 cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0);
00062 cvm::rvector const dl2dx ((2.0/(r0_vec.x*r0_vec.x))*diff.x,
00063 (2.0/(r0_vec.y*r0_vec.y))*diff.y,
00064 (2.0/(r0_vec.z*r0_vec.z))*diff.z);
00065 A1.grad += (-1.0)*dFdl2*dl2dx;
00066 A2.grad += dFdl2*dl2dx;
00067 }
00068 return func;
00069 }
00070
00071
00072
00073 colvar::coordnum::coordnum (std::string const &conf)
00074 : distance (conf), b_anisotropic (false), b_group2_center_only (false)
00075 {
00076 function_type = "coordnum";
00077 x.type (colvarvalue::type_scalar);
00078
00079
00080
00081 bool const b_scale = get_keyval (conf, "cutoff", r0,
00082 cvm::real (4.0 * cvm::unit_angstrom()));
00083
00084 if (get_keyval (conf, "cutoff3", r0_vec,
00085 cvm::rvector (4.0, 4.0, 4.0), parse_silent)) {
00086
00087 if (b_scale)
00088 cvm::fatal_error ("Error: cannot specify \"scale\" and "
00089 "\"scale3\" at the same time.\n");
00090 b_anisotropic = true;
00091
00092 if (r0_vec.x < 0.0) r0_vec.x *= -1.0;
00093 if (r0_vec.y < 0.0) r0_vec.y *= -1.0;
00094 if (r0_vec.z < 0.0) r0_vec.z *= -1.0;
00095 }
00096
00097 get_keyval (conf, "expNumer", en, int (6) );
00098 get_keyval (conf, "expDenom", ed, int (12));
00099
00100 if ( (en%2) || (ed%2) ) {
00101 cvm::fatal_error ("Error: odd exponents provided, can only use even ones.\n");
00102 }
00103
00104 get_keyval (conf, "group2CenterOnly", b_group2_center_only, false);
00105 }
00106
00107
00108 colvar::coordnum::coordnum()
00109 : b_anisotropic (false), b_group2_center_only (false)
00110 {
00111 function_type = "coordnum";
00112 x.type (colvarvalue::type_scalar);
00113 }
00114
00115
00116 void colvar::coordnum::calc_value()
00117 {
00118 x.real_value = 0.0;
00119
00120
00121
00122 group1.reset_atoms_data();
00123 group2.reset_atoms_data();
00124
00125 group1.read_positions();
00126 group2.read_positions();
00127
00128 if (b_group2_center_only) {
00129
00130
00131 cvm::atom group2_com_atom (group2[0]);
00132 group2_com_atom.pos = group2.center_of_mass();
00133
00134 if (b_anisotropic) {
00135 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00136 x.real_value += switching_function<false> (r0_vec, en, ed, *ai1, group2_com_atom);
00137 } else {
00138 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00139 x.real_value += switching_function<false> (r0, en, ed, *ai1, group2_com_atom);
00140 }
00141
00142 } else {
00143
00144 if (b_anisotropic) {
00145 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00146 for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) {
00147 x.real_value += switching_function<false> (r0_vec, en, ed, *ai1, *ai2);
00148 }
00149 } else {
00150 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00151 for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) {
00152 x.real_value += switching_function<false> (r0, en, ed, *ai1, *ai2);
00153 }
00154 }
00155 }
00156 }
00157
00158
00159 void colvar::coordnum::calc_gradients()
00160 {
00161 if (b_group2_center_only) {
00162
00163
00164 cvm::atom group2_com_atom (group2[0]);
00165 group2_com_atom.pos = group2.center_of_mass();
00166
00167 if (b_anisotropic) {
00168 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00169 switching_function<true> (r0_vec, en, ed, *ai1, group2_com_atom);
00170 } else {
00171 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00172 switching_function<true> (r0, en, ed, *ai1, group2_com_atom);
00173 }
00174
00175 group2.set_weighted_gradient (group2_com_atom.grad);
00176
00177 } else {
00178
00179 if (b_anisotropic) {
00180 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00181 for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) {
00182 switching_function<true> (r0_vec, en, ed, *ai1, *ai2);
00183 }
00184 } else {
00185 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++)
00186 for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) {
00187 switching_function<true> (r0, en, ed, *ai1, *ai2);
00188 }
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 }
00204
00205 void colvar::coordnum::apply_force (colvarvalue const &force)
00206 {
00207 if (!group1.noforce)
00208 group1.apply_colvar_force (force.real_value);
00209
00210 if (!group2.noforce)
00211 group2.apply_colvar_force (force.real_value);
00212 }
00213
00214
00215
00216
00217
00218 colvar::h_bond::h_bond (std::string const &conf)
00219 : cvc (conf)
00220 {
00221 function_type = "h_bond";
00222 x.type (colvarvalue::type_scalar);
00223
00224 int a_num, d_num;
00225 get_keyval (conf, "acceptor", a_num, -1);
00226 get_keyval (conf, "donor", d_num, -1);
00227
00228 if ( (a_num == -1) || (d_num == -1) ) {
00229 cvm::fatal_error ("Error: either acceptor or donor undefined.\n");
00230 }
00231
00232 acceptor = cvm::atom (a_num);
00233 donor = cvm::atom (d_num);
00234
00235 get_keyval (conf, "cutoff", r0, (3.3 * cvm::unit_angstrom()));
00236 get_keyval (conf, "expNumer", en, 6);
00237 get_keyval (conf, "expDenom", ed, 8);
00238
00239 if ( (en%2) || (ed%2) ) {
00240 cvm::fatal_error ("Error: odd exponents provided, can only use even ones.\n");
00241 }
00242 }
00243
00244
00245 colvar::h_bond::h_bond (cvm::atom const &acceptor_i,
00246 cvm::atom const &donor_i,
00247 cvm::real r0_i, int en_i, int ed_i)
00248 : acceptor (acceptor_i),
00249 donor (donor_i),
00250 r0 (r0_i), en (en_i), ed (ed_i)
00251 {
00252 function_type = "h_bond";
00253 x.type (colvarvalue::type_scalar);
00254 }
00255
00256
00257 colvar::h_bond::h_bond()
00258 : cvc ()
00259 {
00260 function_type = "h_bond";
00261 x.type (colvarvalue::type_scalar);
00262 }
00263
00264
00265
00266 void colvar::h_bond::calc_value()
00267 {
00268
00269
00270 acceptor.reset_data();
00271 donor.reset_data();
00272
00273 acceptor.read_position();
00274 donor.read_position();
00275
00276 x.real_value = colvar::coordnum::switching_function<false> (r0, en, ed, acceptor, donor);
00277 }
00278
00279
00280 void colvar::h_bond::calc_gradients()
00281 {
00282 colvar::coordnum::switching_function<true> (r0, en, ed, acceptor, donor);
00283 }
00284
00285
00286 void colvar::h_bond::apply_force (colvarvalue const &force)
00287 {
00288 acceptor.apply_force (force.real_value * acceptor.grad);
00289 donor.apply_force (force.real_value * donor.grad);
00290 }
00291
00292
00293