00001 #include <cmath>
00002
00003 #include "colvarmodule.h"
00004 #include "colvarvalue.h"
00005 #include "colvarparse.h"
00006 #include "colvar.h"
00007 #include "colvarcomp.h"
00008
00009
00010
00013
00014
00015
00016
00017 colvar::distance::distance (std::string const &conf, bool twogroups)
00018 : cvc (conf)
00019 {
00020 function_type = "distance";
00021 b_inverse_gradients = true;
00022 b_Jacobian_derivative = true;
00023 if (get_keyval (conf, "forceNoPBC", b_no_PBC, false)) {
00024 cvm::log ("Computing distance using absolute positions (not minimal-image)");
00025 }
00026 if (twogroups && get_keyval (conf, "oneSiteSystemForce", b_1site_force, false)) {
00027 cvm::log ("Computing system force on group 1 only");
00028 }
00029 parse_group (conf, "group1", group1);
00030 atom_groups.push_back (&group1);
00031 if (twogroups) {
00032 parse_group (conf, "group2", group2);
00033 atom_groups.push_back (&group2);
00034 }
00035 x.type (colvarvalue::type_scalar);
00036 }
00037
00038
00039 colvar::distance::distance()
00040 : cvc ()
00041 {
00042 function_type = "distance";
00043 b_inverse_gradients = true;
00044 b_Jacobian_derivative = true;
00045 b_1site_force = false;
00046 x.type (colvarvalue::type_scalar);
00047 }
00048
00049 void colvar::distance::calc_value()
00050 {
00051 group1.reset_atoms_data();
00052 group2.reset_atoms_data();
00053
00054 group1.read_positions();
00055 group2.read_positions();
00056
00057 if (b_no_PBC) {
00058 dist_v = group2.center_of_mass() - group1.center_of_mass();
00059 } else {
00060 dist_v = cvm::position_distance (group1.center_of_mass(),
00061 group2.center_of_mass());
00062 }
00063 x.real_value = dist_v.norm();
00064 }
00065
00066 void colvar::distance::calc_gradients()
00067 {
00068 cvm::rvector const u = dist_v.unit();
00069 group1.set_weighted_gradient (-1.0 * u);
00070 group2.set_weighted_gradient ( u);
00071 }
00072
00073 void colvar::distance::calc_force_invgrads()
00074 {
00075 group1.read_system_forces();
00076 if ( b_1site_force ) {
00077 ft.real_value = -1.0 * (group1.system_force() * dist_v.unit());
00078 } else {
00079 group2.read_system_forces();
00080 ft.real_value = 0.5 * ((group2.system_force() - group1.system_force()) * dist_v.unit());
00081 }
00082 }
00083
00084 void colvar::distance::calc_Jacobian_derivative()
00085 {
00086 jd.real_value = x.real_value ? (2.0 / x.real_value) : 0.0;
00087 }
00088
00089 void colvar::distance::apply_force (colvarvalue const &force)
00090 {
00091 if (!group1.noforce)
00092 group1.apply_colvar_force (force);
00093
00094 if (!group2.noforce)
00095 group2.apply_colvar_force (force);
00096 }
00097
00098
00099
00100 colvar::distance_vec::distance_vec (std::string const &conf)
00101 : distance (conf)
00102 {
00103 function_type = "distance_vec";
00104 x.type (colvarvalue::type_vector);
00105 }
00106
00107 colvar::distance_vec::distance_vec()
00108 : distance()
00109 {
00110 function_type = "distance_vec";
00111 x.type (colvarvalue::type_vector);
00112 }
00113
00114 void colvar::distance_vec::calc_value()
00115 {
00116 group1.reset_atoms_data();
00117 group2.reset_atoms_data();
00118
00119 group1.read_positions();
00120 group2.read_positions();
00121
00122 if (b_no_PBC) {
00123 x.rvector_value = group2.center_of_mass() - group1.center_of_mass();
00124 } else {
00125 x.rvector_value = cvm::position_distance (group1.center_of_mass(),
00126 group2.center_of_mass());
00127 }
00128 }
00129
00130 void colvar::distance_vec::calc_gradients()
00131 {
00132
00133
00134 }
00135
00136 void colvar::distance_vec::apply_force (colvarvalue const &force)
00137 {
00138 if (!group1.noforce)
00139 group1.apply_force (-1.0 * force.rvector_value);
00140
00141 if (!group2.noforce)
00142 group2.apply_force ( force.rvector_value);
00143 }
00144
00145
00146
00147 colvar::distance_z::distance_z (std::string const &conf)
00148 : cvc (conf)
00149 {
00150 function_type = "distance_z";
00151 b_inverse_gradients = true;
00152 b_Jacobian_derivative = true;
00153 x.type (colvarvalue::type_scalar);
00154
00155
00156
00157 if (period != 0.0)
00158 b_periodic = true;
00159
00160 if ((wrap_center != 0.0) && (period == 0.0)) {
00161 cvm::fatal_error ("Error: wrapAround was defined in a distanceZ component,"
00162 " but its period has not been set.\n");
00163 }
00164
00165 parse_group (conf, "main", main);
00166 parse_group (conf, "ref", ref1);
00167 atom_groups.push_back (&main);
00168 atom_groups.push_back (&ref1);
00169
00170 parse_group (conf, "ref2", ref2, true);
00171
00172 if (ref2.size()) {
00173 atom_groups.push_back (&ref2);
00174 cvm::log ("Using axis joining the centers of mass of groups \"ref\" and \"ref2\"");
00175 fixed_axis = false;
00176 if (key_lookup (conf, "axis"))
00177 cvm::log ("Warning: explicit axis definition will be ignored!");
00178 } else {
00179 if (get_keyval (conf, "axis", axis, cvm::rvector (0.0, 0.0, 1.0))) {
00180 if (axis.norm2() == 0.0)
00181 cvm::fatal_error ("Axis vector is zero!");
00182 axis = axis.unit();
00183 }
00184 fixed_axis = true;
00185 }
00186
00187 if (get_keyval (conf, "forceNoPBC", b_no_PBC, false)) {
00188 cvm::log ("Computing distance using absolute positions (not minimal-image)");
00189 }
00190 if (get_keyval (conf, "oneSiteSystemForce", b_1site_force, false)) {
00191 cvm::log ("Computing system force on group \"main\" only");
00192 }
00193 }
00194
00195 colvar::distance_z::distance_z()
00196 {
00197 function_type = "distance_z";
00198 b_inverse_gradients = true;
00199 b_Jacobian_derivative = true;
00200 x.type (colvarvalue::type_scalar);
00201 }
00202
00203 void colvar::distance_z::calc_value()
00204 {
00205 main.reset_atoms_data();
00206 ref1.reset_atoms_data();
00207
00208 main.read_positions();
00209 ref1.read_positions();
00210
00211 if (fixed_axis) {
00212 if (b_no_PBC) {
00213 dist_v = main.center_of_mass() - ref1.center_of_mass();
00214 } else {
00215 dist_v = cvm::position_distance (ref1.center_of_mass(),
00216 main.center_of_mass());
00217 }
00218 } else {
00219 ref2.reset_atoms_data();
00220 ref2.read_positions();
00221
00222 if (b_no_PBC) {
00223 dist_v = main.center_of_mass() -
00224 (0.5 * (ref1.center_of_mass() + ref2.center_of_mass()));
00225 axis = ref2.center_of_mass() - ref1.center_of_mass();
00226 } else {
00227 dist_v = cvm::position_distance (0.5 * (ref1.center_of_mass() +
00228 ref2.center_of_mass()), main.center_of_mass());
00229 axis = cvm::position_distance (ref1.center_of_mass(), ref2.center_of_mass());
00230 }
00231 axis_norm = axis.norm();
00232 axis = axis.unit();
00233 }
00234 x.real_value = axis * dist_v;
00235 this->wrap (x);
00236 }
00237
00238 void colvar::distance_z::calc_gradients()
00239 {
00240 main.set_weighted_gradient ( axis );
00241
00242 if (fixed_axis) {
00243 ref1.set_weighted_gradient (-1.0 * axis);
00244 } else {
00245 if (b_no_PBC) {
00246 ref1.set_weighted_gradient ( 1.0 / axis_norm * (main.center_of_mass() - ref2.center_of_mass() -
00247 x.real_value * axis ));
00248 ref2.set_weighted_gradient ( 1.0 / axis_norm * (ref1.center_of_mass() - main.center_of_mass() +
00249 x.real_value * axis ));
00250 } else {
00251 ref1.set_weighted_gradient ( 1.0 / axis_norm * (
00252 cvm::position_distance (ref2.center_of_mass(), main.center_of_mass()) - x.real_value * axis ));
00253 ref2.set_weighted_gradient ( 1.0 / axis_norm * (
00254 cvm::position_distance (main.center_of_mass(), ref1.center_of_mass()) + x.real_value * axis ));
00255 }
00256 }
00257 }
00258
00259 void colvar::distance_z::calc_force_invgrads()
00260 {
00261 main.read_system_forces();
00262
00263 if (fixed_axis && !b_1site_force) {
00264 ref1.read_system_forces();
00265 ft.real_value = 0.5 * ((main.system_force() - ref1.system_force()) * axis);
00266 } else {
00267 ft.real_value = main.system_force() * axis;
00268 }
00269 }
00270
00271 void colvar::distance_z::calc_Jacobian_derivative()
00272 {
00273 jd.real_value = 0.0;
00274 }
00275
00276 void colvar::distance_z::apply_force (colvarvalue const &force)
00277 {
00278 if (!ref1.noforce)
00279 ref1.apply_colvar_force (force.real_value);
00280
00281 if (ref2.size() && !ref2.noforce)
00282 ref2.apply_colvar_force (force.real_value);
00283
00284 if (!main.noforce)
00285 main.apply_colvar_force (force.real_value);
00286 }
00287
00288
00289
00290 colvar::distance_xy::distance_xy (std::string const &conf)
00291 : distance_z (conf)
00292 {
00293 function_type = "distance_xy";
00294 b_inverse_gradients = true;
00295 b_Jacobian_derivative = true;
00296 x.type (colvarvalue::type_scalar);
00297 }
00298
00299 colvar::distance_xy::distance_xy()
00300 : distance_z()
00301 {
00302 function_type = "distance_xy";
00303 b_inverse_gradients = true;
00304 b_Jacobian_derivative = true;
00305 x.type (colvarvalue::type_scalar);
00306 }
00307
00308 void colvar::distance_xy::calc_value()
00309 {
00310 ref1.reset_atoms_data();
00311 main.reset_atoms_data();
00312
00313 ref1.read_positions();
00314 main.read_positions();
00315
00316 if (b_no_PBC) {
00317 dist_v = main.center_of_mass() - ref1.center_of_mass();
00318 } else {
00319 dist_v = cvm::position_distance (ref1.center_of_mass(),
00320 main.center_of_mass());
00321 }
00322 if (!fixed_axis) {
00323 ref2.reset_atoms_data();
00324 ref2.read_positions();
00325
00326 if (b_no_PBC) {
00327 v12 = ref2.center_of_mass() - ref1.center_of_mass();
00328 } else {
00329 v12 = cvm::position_distance (ref1.center_of_mass(), ref2.center_of_mass());
00330 }
00331 axis_norm = v12.norm();
00332 axis = v12.unit();
00333 }
00334
00335 dist_v_ortho = dist_v - (dist_v * axis) * axis;
00336 x.real_value = dist_v_ortho.norm();
00337 }
00338
00339 void colvar::distance_xy::calc_gradients()
00340 {
00341
00342
00343 cvm::real A;
00344 cvm::real x_inv;
00345
00346 if (x.real_value == 0.0) return;
00347 x_inv = 1.0 / x.real_value;
00348
00349 if (fixed_axis) {
00350 ref1.set_weighted_gradient (-1.0 * x_inv * dist_v_ortho);
00351 main.set_weighted_gradient ( x_inv * dist_v_ortho);
00352 } else {
00353 if (b_no_PBC) {
00354 v13 = main.center_of_mass() - ref1.center_of_mass();
00355 } else {
00356 v13 = cvm::position_distance (ref1.center_of_mass(), main.center_of_mass());
00357 }
00358 A = (dist_v * axis) / axis_norm;
00359
00360 ref1.set_weighted_gradient ( (A - 1.0) * x_inv * dist_v_ortho);
00361 ref2.set_weighted_gradient ( -A * x_inv * dist_v_ortho);
00362 main.set_weighted_gradient ( 1.0 * x_inv * dist_v_ortho);
00363 }
00364 }
00365
00366 void colvar::distance_xy::calc_force_invgrads()
00367 {
00368 main.read_system_forces();
00369
00370 if (fixed_axis && !b_1site_force) {
00371 ref1.read_system_forces();
00372 ft.real_value = 0.5 / x.real_value * ((main.system_force() - ref1.system_force()) * dist_v_ortho);
00373 } else {
00374 ft.real_value = 1.0 / x.real_value * main.system_force() * dist_v_ortho;
00375 }
00376 }
00377
00378 void colvar::distance_xy::calc_Jacobian_derivative()
00379 {
00380 jd.real_value = x.real_value ? (1.0 / x.real_value) : 0.0;
00381 }
00382
00383 void colvar::distance_xy::apply_force (colvarvalue const &force)
00384 {
00385 if (!ref1.noforce)
00386 ref1.apply_colvar_force (force.real_value);
00387
00388 if (ref2.size() && !ref2.noforce)
00389 ref2.apply_colvar_force (force.real_value);
00390
00391 if (!main.noforce)
00392 main.apply_colvar_force (force.real_value);
00393 }
00394
00395
00396
00397 colvar::min_distance::min_distance (std::string const &conf)
00398 : distance (conf)
00399 {
00400 function_type = "min_distance";
00401 x.type (colvarvalue::type_scalar);
00402
00403 get_keyval (conf, "smoothing", smoothing, (1.0 * cvm::unit_angstrom()));
00404 }
00405
00406 colvar::min_distance::min_distance()
00407 : distance()
00408 {
00409 function_type = "min_distance";
00410 x.type (colvarvalue::type_scalar);
00411 }
00412
00413 void colvar::min_distance::calc_value()
00414 {
00415 group1.reset_atoms_data();
00416 group2.reset_atoms_data();
00417
00418 group1.read_positions();
00419 group2.read_positions();
00420
00421 x.real_value = 0.0;
00422
00423 bool zero_dist = false;
00424
00425 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) {
00426 for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) {
00427 cvm::rvector const dv = cvm::position_distance (ai1->pos, ai2->pos);
00428 cvm::real const d = dv.norm();
00429 if (d > 0.0)
00430 x.real_value += std::exp (smoothing / d);
00431 else
00432 zero_dist = true;
00433 }
00434 }
00435
00436 x.real_value = zero_dist ? 0.0 : smoothing/(std::log (x.real_value));
00437 }
00438
00439 void colvar::min_distance::calc_gradients()
00440 {
00441 if (x.real_value > 0.0) {
00442 cvm::real const sum = std::exp (smoothing/x.real_value);
00443 cvm::real const dxdsum = -1.0 *
00444 (x.real_value/smoothing) * (x.real_value/smoothing) *
00445 (1.0 / sum);
00446
00447 for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) {
00448 for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) {
00449 cvm::rvector const dv = cvm::position_distance (ai1->pos, ai2->pos);
00450 cvm::real const d = dv.norm();
00451 if (d > 0.0) {
00452 cvm::rvector const dvu = dv / dv.norm();
00453 ai1->grad += dxdsum * std::exp (smoothing / d) *
00454 smoothing * (-1.0/(d*d)) * (-1.0) * dvu;
00455 ai2->grad += dxdsum * std::exp (smoothing / d) *
00456 smoothing * (-1.0/(d*d)) * dvu;
00457 }
00458 }
00459 }
00460 }
00461 }
00462
00463 void colvar::min_distance::apply_force (colvarvalue const &force)
00464 {
00465 if (!group1.noforce)
00466 group1.apply_colvar_force (force.real_value);
00467
00468 if (!group2.noforce)
00469 group2.apply_colvar_force (force.real_value);
00470 }
00471
00472
00473
00474 colvar::distance_dir::distance_dir (std::string const &conf)
00475 : distance (conf)
00476 {
00477 function_type = "distance_dir";
00478 x.type (colvarvalue::type_unitvector);
00479 }
00480
00481
00482 colvar::distance_dir::distance_dir()
00483 : distance()
00484 {
00485 function_type = "distance_dir";
00486 x.type (colvarvalue::type_unitvector);
00487 }
00488
00489
00490 void colvar::distance_dir::calc_value()
00491 {
00492 group1.reset_atoms_data();
00493 group2.reset_atoms_data();
00494
00495 group1.read_positions();
00496 group2.read_positions();
00497
00498 if (b_no_PBC) {
00499 dist_v = group2.center_of_mass() - group1.center_of_mass();
00500 } else {
00501 dist_v = cvm::position_distance (group1.center_of_mass(),
00502 group2.center_of_mass());
00503 }
00504 x.rvector_value = dist_v.unit();
00505 }
00506
00507
00508 void colvar::distance_dir::calc_gradients()
00509 {
00510
00511
00512
00513 }
00514
00515
00516 void colvar::distance_dir::apply_force (colvarvalue const &force)
00517 {
00518
00519 cvm::real const iprod = force.rvector_value * x.rvector_value;
00520 cvm::rvector const force_tang = force.rvector_value - iprod * x.rvector_value;
00521
00522 if (!group1.noforce)
00523 group1.apply_force (-1.0 * force_tang);
00524
00525 if (!group2.noforce)
00526 group2.apply_force ( force_tang);
00527 }
00528
00529
00530
00531
00532 colvar::gyration::gyration (std::string const &conf)
00533 : cvc (conf)
00534 {
00535 function_type = "gyration";
00536 b_inverse_gradients = true;
00537 b_Jacobian_derivative = true;
00538 parse_group (conf, "atoms", atoms);
00539 atom_groups.push_back (&atoms);
00540 x.type (colvarvalue::type_scalar);
00541 }
00542
00543
00544 colvar::gyration::gyration()
00545 {
00546 function_type = "gyration";
00547 b_inverse_gradients = true;
00548 b_Jacobian_derivative = true;
00549 x.type (colvarvalue::type_scalar);
00550 }
00551
00552
00553 void colvar::gyration::calc_value()
00554 {
00555 atoms.reset_atoms_data();
00556 atoms.read_positions();
00557 atoms.apply_translation ((-1.0) * atoms.center_of_geometry());
00558
00559 x.real_value = 0.0;
00560 for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) {
00561 x.real_value += (ai->mass/atoms.total_mass) * (ai->pos).norm2();
00562 }
00563 x.real_value = std::sqrt (x.real_value);
00564 }
00565
00566
00567 void colvar::gyration::calc_gradients()
00568 {
00569 cvm::real const drdx = 1.0/(cvm::real (atoms.size()) * x.real_value);
00570 for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) {
00571 ai->grad = drdx * ai->pos;
00572 }
00573 }
00574
00575
00576 void colvar::gyration::calc_force_invgrads()
00577 {
00578 atoms.read_system_forces();
00579
00580 cvm::real const dxdr = 1.0/x.real_value;
00581 ft.real_value = 0.0;
00582
00583 for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) {
00584 ft.real_value += dxdr * ai->pos * ai->system_force;
00585 }
00586 }
00587
00588
00589 void colvar::gyration::calc_Jacobian_derivative()
00590 {
00591 jd = x.real_value ? (3.0 * cvm::real (atoms.size()) - 4.0) / x.real_value : 0.0;
00592 }
00593
00594
00595 void colvar::gyration::apply_force (colvarvalue const &force)
00596 {
00597 if (!atoms.noforce)
00598 atoms.apply_colvar_force (force.real_value);
00599 }
00600
00601
00602
00603 colvar::rmsd::rmsd (std::string const &conf)
00604 : orientation (conf)
00605 {
00606 b_inverse_gradients = true;
00607 b_Jacobian_derivative = true;
00608 function_type = "rmsd";
00609 x.type (colvarvalue::type_scalar);
00610
00611 ref_pos_sum2 = 0.0;
00612 for (size_t i = 0; i < ref_pos.size(); i++) {
00613 ref_pos_sum2 += ref_pos[i].norm2();
00614 }
00615 }
00616
00617
00618 void colvar::rmsd::calc_value()
00619 {
00620 atoms.reset_atoms_data();
00621 atoms.read_positions();
00622
00623 atoms_cog = atoms.center_of_geometry();
00624 rot.calc_optimal_rotation (ref_pos, atoms.positions_shifted (-1.0 * atoms_cog));
00625
00626 cvm::real group_pos_sum2 = 0.0;
00627 for (size_t i = 0; i < atoms.size(); i++) {
00628 group_pos_sum2 += (atoms[i].pos - atoms_cog).norm2();
00629 }
00630
00631
00632 cvm::real const MSD = 1.0/(cvm::real (atoms.size())) *
00633 ( group_pos_sum2 + ref_pos_sum2 - 2.0 * rot.lambda );
00634
00635 x.real_value = (MSD > 0.0) ? std::sqrt (MSD) : 0.0;
00636 }
00637
00638
00639 void colvar::rmsd::calc_gradients()
00640 {
00641 cvm::real const drmsddx2 = (x.real_value > 0.0) ?
00642 0.5 / (x.real_value * cvm::real (atoms.size())) :
00643 0.0;
00644
00645 for (size_t ia = 0; ia < atoms.size(); ia++) {
00646 atoms[ia].grad = (drmsddx2 * 2.0 * (atoms[ia].pos - atoms_cog -
00647 rot.q.rotate (ref_pos[ia])));
00648 }
00649 }
00650
00651
00652 void colvar::rmsd::apply_force (colvarvalue const &force)
00653 {
00654 if (!atoms.noforce)
00655 atoms.apply_colvar_force (force.real_value);
00656 }
00657
00658
00659 void colvar::rmsd::calc_force_invgrads()
00660 {
00661 atoms.read_system_forces();
00662 ft.real_value = 0.0;
00663
00664
00665
00666 for (size_t ia = 0; ia < atoms.size(); ia++) {
00667 ft.real_value += atoms[ia].grad * atoms[ia].system_force;
00668 }
00669 ft.real_value *= atoms.size();
00670 }
00671
00672
00673 void colvar::rmsd::calc_Jacobian_derivative()
00674 {
00675
00676 cvm::real divergence = 0.0;
00677
00678
00679 cvm::matrix2d <cvm::rvector, 3, 3> grad_rot_mat;
00680
00681
00682 cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
00683
00684 for (size_t ia = 0; ia < atoms.size(); ia++) {
00685
00686
00687 cvm::vector1d< cvm::rvector, 4 > &dq = rot.dQ0_2[ia];
00688
00689 g11 = 2.0 * (rot.q)[1]*dq[1];
00690 g22 = 2.0 * (rot.q)[2]*dq[2];
00691 g33 = 2.0 * (rot.q)[3]*dq[3];
00692 g01 = (rot.q)[0]*dq[1] + (rot.q)[1]*dq[0];
00693 g02 = (rot.q)[0]*dq[2] + (rot.q)[2]*dq[0];
00694 g03 = (rot.q)[0]*dq[3] + (rot.q)[3]*dq[0];
00695 g12 = (rot.q)[1]*dq[2] + (rot.q)[2]*dq[1];
00696 g13 = (rot.q)[1]*dq[3] + (rot.q)[3]*dq[1];
00697 g23 = (rot.q)[2]*dq[3] + (rot.q)[3]*dq[2];
00698
00699
00700 grad_rot_mat[0][0] = -2.0 * (g22 + g33);
00701 grad_rot_mat[1][0] = 2.0 * (g12 + g03);
00702 grad_rot_mat[2][0] = 2.0 * (g13 - g02);
00703 grad_rot_mat[0][1] = 2.0 * (g12 - g03);
00704 grad_rot_mat[1][1] = -2.0 * (g11 + g33);
00705 grad_rot_mat[2][1] = 2.0 * (g01 + g23);
00706 grad_rot_mat[0][2] = 2.0 * (g02 + g13);
00707 grad_rot_mat[1][2] = 2.0 * (g23 - g01);
00708 grad_rot_mat[2][2] = -2.0 * (g11 + g22);
00709
00710 cvm::atom_pos &y = ref_pos[ia];
00711
00712 for (size_t i = 0; i < 3; i++) {
00713 for (size_t j = 0; j < 3; j++) {
00714 divergence += grad_rot_mat[i][j][i] * y[j];
00715 }
00716 }
00717 }
00718
00719 jd.real_value = x.real_value > 0.0 ? (3.0 * atoms.size() - 4.0 - divergence) / x.real_value : 0.0;
00720 }
00721
00722
00723
00724 colvar::logmsd::logmsd (std::string const &conf)
00725 : orientation (conf)
00726 {
00727 b_inverse_gradients = true;
00728 b_Jacobian_derivative = true;
00729 function_type = "logmsd";
00730 x.type (colvarvalue::type_scalar);
00731
00732 ref_pos_sum2 = 0.0;
00733 for (size_t i = 0; i < ref_pos.size(); i++) {
00734 ref_pos_sum2 += ref_pos[i].norm2();
00735 }
00736 }
00737
00738
00739 void colvar::logmsd::calc_value()
00740 {
00741 atoms.reset_atoms_data();
00742 atoms.read_positions();
00743
00744 if (cvm::debug())
00745 cvm::log ("colvar::logmsd: current com: "+
00746 cvm::to_str (atoms.center_of_mass())+"\n");
00747
00748 atoms_cog = atoms.center_of_geometry();
00749 rot.calc_optimal_rotation (ref_pos, atoms.positions_shifted (-1.0 * atoms_cog));
00750
00751 cvm::real group_pos_sum2 = 0.0;
00752 for (size_t i = 0; i < atoms.size(); i++) {
00753 group_pos_sum2 += (atoms[i].pos-atoms_cog).norm2();
00754 }
00755
00756
00757 MSD = 1.0/(cvm::real (atoms.size())) *
00758 ( group_pos_sum2 + ref_pos_sum2 - 2.0 * rot.lambda );
00759
00760 x.real_value = (MSD > 0.0) ? std::log(MSD) : 0.0;
00761 }
00762
00763
00764 void colvar::logmsd::calc_gradients()
00765 {
00766 cvm::real fact = (MSD > 0.0) ? 2.0/(cvm::real (atoms.size()) * MSD) : 0.0;
00767
00768 for (size_t ia = 0; ia < atoms.size(); ia++) {
00769 atoms[ia].grad = fact * (atoms[ia].pos - atoms_cog - rot.dL0_2[ia]);
00770 }
00771 }
00772
00773
00774 void colvar::logmsd::apply_force (colvarvalue const &force)
00775 {
00776 if (!atoms.noforce)
00777 atoms.apply_colvar_force (force.real_value);
00778 }
00779
00780
00781 void colvar::logmsd::calc_force_invgrads()
00782 {
00783 atoms.read_system_forces();
00784 ft.real_value = 0.0;
00785
00786
00787
00788 for (size_t ia = 0; ia < atoms.size(); ia++) {
00789 ft.real_value += atoms[ia].grad * atoms[ia].system_force;
00790 }
00791 ft.real_value *= atoms.size() * MSD / 4.0;
00792 }
00793
00794
00795 void colvar::logmsd::calc_Jacobian_derivative()
00796 {
00797
00798 cvm::real divergence = 0.0;
00799
00800
00801 cvm::matrix2d <cvm::rvector, 3, 3> grad_rot_mat;
00802
00803
00804 cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
00805
00806 for (size_t ia = 0; ia < atoms.size(); ia++) {
00807
00808
00809 cvm::vector1d< cvm::rvector, 4 > &dq = rot.dQ0_2[ia];
00810
00811 g11 = 2.0 * (rot.q)[1]*dq[1];
00812 g22 = 2.0 * (rot.q)[2]*dq[2];
00813 g33 = 2.0 * (rot.q)[3]*dq[3];
00814 g01 = (rot.q)[0]*dq[1] + (rot.q)[1]*dq[0];
00815 g02 = (rot.q)[0]*dq[2] + (rot.q)[2]*dq[0];
00816 g03 = (rot.q)[0]*dq[3] + (rot.q)[3]*dq[0];
00817 g12 = (rot.q)[1]*dq[2] + (rot.q)[2]*dq[1];
00818 g13 = (rot.q)[1]*dq[3] + (rot.q)[3]*dq[1];
00819 g23 = (rot.q)[2]*dq[3] + (rot.q)[3]*dq[2];
00820
00821
00822
00823 grad_rot_mat[0][0] = -2.0 * (g22 + g33);
00824 grad_rot_mat[1][0] = 2.0 * (g12 + g03);
00825 grad_rot_mat[2][0] = 2.0 * (g13 - g02);
00826 grad_rot_mat[0][1] = 2.0 * (g12 - g03);
00827 grad_rot_mat[1][1] = -2.0 * (g11 + g33);
00828 grad_rot_mat[2][1] = 2.0 * (g01 + g23);
00829 grad_rot_mat[0][2] = 2.0 * (g02 + g13);
00830 grad_rot_mat[1][2] = 2.0 * (g23 - g01);
00831 grad_rot_mat[2][2] = -2.0 * (g11 + g22);
00832
00833 cvm::atom_pos &y = ref_pos[ia];
00834
00835 for (size_t i = 0; i < 3; i++) {
00836 for (size_t j = 0; j < 3; j++) {
00837 divergence += grad_rot_mat[i][j][i] * y[j];
00838 }
00839 }
00840 }
00841
00842 jd.real_value = (3.0 * atoms.size() - 3.0 - divergence) / 2.0;
00843 }
00844
00845
00846
00847 colvar::eigenvector::eigenvector (std::string const &conf)
00848 : cvc (conf)
00849 {
00850 b_inverse_gradients = true;
00851 b_Jacobian_derivative = true;
00852 function_type = "eigenvector";
00853 x.type (colvarvalue::type_scalar);
00854
00855 parse_group (conf, "atoms", atoms);
00856 atom_groups.push_back (&atoms);
00857
00858 if (atoms.b_rotate) {
00859 cvm::fatal_error ("Error: rotateReference should be disabled:"
00860 "eigenvector component will set it internally.");
00861 }
00862
00863 if (get_keyval (conf, "refPositions", ref_pos, ref_pos)) {
00864 cvm::log ("Using reference positions from input file.\n");
00865 if (ref_pos.size() != atoms.size()) {
00866 cvm::fatal_error ("Error: reference positions do not "
00867 "match the number of requested atoms.\n");
00868 }
00869 }
00870
00871 {
00872 std::string file_name;
00873 if (get_keyval (conf, "refPositionsFile", file_name)) {
00874
00875 std::string file_col;
00876 double file_col_value;
00877 if (get_keyval (conf, "refPositionsCol", file_col, std::string (""))) {
00878
00879 bool found = get_keyval (conf, "refPositionsColValue", file_col_value, 0.0);
00880 if (found && !file_col_value)
00881 cvm::fatal_error ("Error: refPositionsColValue, "
00882 "if provided, must be non-zero.\n");
00883 } else {
00884
00885 atoms.create_sorted_ids();
00886 }
00887
00888 ref_pos.resize (atoms.size());
00889 cvm::load_coords (file_name.c_str(), ref_pos, atoms.sorted_ids, file_col, file_col_value);
00890 }
00891 }
00892
00893
00894 atoms.b_center = true;
00895 atoms.b_rotate = true;
00896 atoms.ref_pos = ref_pos;
00897
00898
00899 if (get_keyval (conf, "vector", eigenvec, eigenvec)) {
00900 cvm::log ("Using vector components from input file.\n");
00901 if (eigenvec.size() != atoms.size()) {
00902 cvm::fatal_error ("Error: vector components do not "
00903 "match the number of requested atoms.\n");
00904 }
00905 }
00906
00907 {
00908 std::string file_name;
00909 if (get_keyval (conf, "vectorFile", file_name)) {
00910
00911 std::string file_col;
00912 if (!get_keyval (conf, "vectorCol", file_col, std::string (""))) {
00913 cvm::fatal_error ("Error: parameter vectorCol is required if vectorFile is set.\n");
00914 }
00915
00916 double file_col_value;
00917 bool found = get_keyval (conf, "vectorColValue", file_col_value, 0.0);
00918 if (found && !file_col_value)
00919 cvm::fatal_error ("Error: eigenvectorColValue, "
00920 "if provided, must be non-zero.\n");
00921
00922 eigenvec.resize (atoms.size());
00923 cvm::load_coords (file_name.c_str(), eigenvec, atoms.sorted_ids, file_col, file_col_value);
00924 }
00925 }
00926
00927 if (!ref_pos.size() || !eigenvec.size()) {
00928 cvm::fatal_error ("Error: both reference coordinates"
00929 "and eigenvector must be defined.\n");
00930 }
00931
00932 cvm::rvector center (0.0, 0.0, 0.0);
00933 eigenvec_invnorm2 = 0.0;
00934
00935 for (size_t i = 0; i < atoms.size(); i++) {
00936 center += eigenvec[i];
00937 }
00938
00939 cvm::log ("Subtracting sum of eigenvector components: " + cvm::to_str (center) + "\n");
00940
00941 for (size_t i = 0; i < atoms.size(); i++) {
00942 eigenvec[i] = eigenvec[i] - center;
00943 eigenvec_invnorm2 += eigenvec[i].norm2();
00944 }
00945 eigenvec_invnorm2 = 1.0 / eigenvec_invnorm2;
00946
00947
00948
00949 atoms.rot.request_group1_gradients(atoms.size());
00950 atoms.rot.request_group2_gradients(atoms.size());
00951 }
00952
00953
00954 void colvar::eigenvector::calc_value()
00955 {
00956 atoms.reset_atoms_data();
00957 atoms.read_positions();
00958
00959 x.real_value = 0.0;
00960 for (size_t i = 0; i < atoms.size(); i++) {
00961 x.real_value += (atoms[i].pos - ref_pos[i]) * eigenvec[i];
00962 }
00963 }
00964
00965
00966 void colvar::eigenvector::calc_gradients()
00967 {
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977 for (size_t ia = 0; ia < atoms.size(); ia++) {
00978 atoms[ia].grad = eigenvec[ia];
00979 }
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042 }
01043
01044
01045 void colvar::eigenvector::apply_force (colvarvalue const &force)
01046 {
01047 if (!atoms.noforce)
01048 atoms.apply_colvar_force (force.real_value);
01049 }
01050
01051
01052 void colvar::eigenvector::calc_force_invgrads()
01053 {
01054 atoms.read_system_forces();
01055 ft.real_value = 0.0;
01056
01057 for (size_t ia = 0; ia < atoms.size(); ia++) {
01058 ft.real_value += eigenvec_invnorm2 * atoms[ia].grad *
01059 atoms[ia].system_force;
01060 }
01061 }
01062
01063
01064 void colvar::eigenvector::calc_Jacobian_derivative()
01065 {
01066
01067 cvm::matrix2d <cvm::rvector, 3, 3> grad_rot_mat;
01068 cvm::quaternion &quat0 = atoms.rot.q;
01069
01070
01071 cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
01072
01073 cvm::atom_pos x_relative;
01074 cvm::real sum = 0.0;
01075
01076 for (size_t ia = 0; ia < atoms.size(); ia++) {
01077
01078
01079
01080
01081 cvm::vector1d< cvm::rvector, 4 > &dq_1 = atoms.rot.dQ0_1[ia];
01082
01083 g11 = 2.0 * quat0[1]*dq_1[1];
01084 g22 = 2.0 * quat0[2]*dq_1[2];
01085 g33 = 2.0 * quat0[3]*dq_1[3];
01086 g01 = quat0[0]*dq_1[1] + quat0[1]*dq_1[0];
01087 g02 = quat0[0]*dq_1[2] + quat0[2]*dq_1[0];
01088 g03 = quat0[0]*dq_1[3] + quat0[3]*dq_1[0];
01089 g12 = quat0[1]*dq_1[2] + quat0[2]*dq_1[1];
01090 g13 = quat0[1]*dq_1[3] + quat0[3]*dq_1[1];
01091 g23 = quat0[2]*dq_1[3] + quat0[3]*dq_1[2];
01092
01093
01094
01095 grad_rot_mat[0][0] = -2.0 * (g22 + g33);
01096 grad_rot_mat[0][1] = 2.0 * (g12 + g03);
01097 grad_rot_mat[0][2] = 2.0 * (g13 - g02);
01098 grad_rot_mat[1][0] = 2.0 * (g12 - g03);
01099 grad_rot_mat[1][1] = -2.0 * (g11 + g33);
01100 grad_rot_mat[1][2] = 2.0 * (g01 + g23);
01101 grad_rot_mat[2][0] = 2.0 * (g02 + g13);
01102 grad_rot_mat[2][1] = 2.0 * (g23 - g01);
01103 grad_rot_mat[2][2] = -2.0 * (g11 + g22);
01104
01105 for (size_t i = 0; i < 3; i++) {
01106 for (size_t j = 0; j < 3; j++) {
01107 sum += grad_rot_mat[i][j][i] * eigenvec[ia][j];
01108 }
01109 }
01110 }
01111
01112 jd.real_value = sum * std::sqrt (eigenvec_invnorm2);
01113 }