Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

colvarcomp_coordnums.C

Go to the documentation of this file.
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   // Assume en and ed are even integers, and avoid sqrt in the following
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   // Assume en and ed are even integers, and avoid sqrt in the following
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   // group1 and group2 are already initialized by distance()
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     // remove meaningless negative signs
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   // these are necessary: for each atom, gradients are summed together
00121   // by multiple calls to switching_function()
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     // create a fake atom to hold the group2 com coordinates
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     // create a fake atom to hold the group2 com coordinates
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   //   if (cvm::debug()) {
00193   //     for (size_t i = 0; i < group1.size(); i++) {
00194   //       cvm::log ("atom["+cvm::to_str (group1[i].id+1)+"] gradient: "+
00195   //                 cvm::to_str (group1[i].grad)+"\n");
00196   //     }
00197 
00198   //     for (size_t i = 0; i < group2.size(); i++) {
00199   //       cvm::log ("atom["+cvm::to_str (group2[i].id+1)+"] gradient: "+
00200   //                 cvm::to_str (group2[i].grad)+"\n");
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 // h_bond member functions
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   // this is necessary, because switching_function() will sum the new
00269   // gradient to the current one
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 

Generated on Mon Nov 23 04:59:18 2009 for NAMD by  doxygen 1.3.9.1