00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <algorithm>
00011
00012 #include "colvarmodule.h"
00013 #include "colvarvalue.h"
00014 #include "colvarparse.h"
00015 #include "colvar.h"
00016 #include "colvarcomp.h"
00017
00018
00019
00020 colvar::distance::distance(std::string const &conf)
00021 : cvc(conf)
00022 {
00023 set_function_type("distance");
00024 init_as_distance();
00025
00026 provide(f_cvc_inv_gradient);
00027 provide(f_cvc_Jacobian);
00028 enable(f_cvc_com_based);
00029
00030 group1 = parse_group(conf, "group1");
00031 group2 = parse_group(conf, "group2");
00032
00033 init_total_force_params(conf);
00034 }
00035
00036
00037 colvar::distance::distance()
00038 : cvc()
00039 {
00040 set_function_type("distance");
00041 init_as_distance();
00042
00043 provide(f_cvc_inv_gradient);
00044 provide(f_cvc_Jacobian);
00045 enable(f_cvc_com_based);
00046 }
00047
00048
00049 void colvar::distance::calc_value()
00050 {
00051 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00052 dist_v = group2->center_of_mass() - group1->center_of_mass();
00053 } else {
00054 dist_v = cvm::position_distance(group1->center_of_mass(),
00055 group2->center_of_mass());
00056 }
00057 x.real_value = dist_v.norm();
00058 }
00059
00060
00061 void colvar::distance::calc_gradients()
00062 {
00063 cvm::rvector const u = dist_v.unit();
00064 group1->set_weighted_gradient(-1.0 * u);
00065 group2->set_weighted_gradient( u);
00066 }
00067
00068
00069 void colvar::distance::calc_force_invgrads()
00070 {
00071 group1->read_total_forces();
00072 if (is_enabled(f_cvc_one_site_total_force)) {
00073 ft.real_value = -1.0 * (group1->total_force() * dist_v.unit());
00074 } else {
00075 group2->read_total_forces();
00076 ft.real_value = 0.5 * ((group2->total_force() - group1->total_force()) * dist_v.unit());
00077 }
00078 }
00079
00080
00081 void colvar::distance::calc_Jacobian_derivative()
00082 {
00083 jd.real_value = x.real_value ? (2.0 / x.real_value) : 0.0;
00084 }
00085
00086
00087 void colvar::distance::apply_force(colvarvalue const &force)
00088 {
00089 if (!group1->noforce)
00090 group1->apply_colvar_force(force.real_value);
00091
00092 if (!group2->noforce)
00093 group2->apply_colvar_force(force.real_value);
00094 }
00095
00096
00097 simple_scalar_dist_functions(distance)
00098
00099
00100
00101 colvar::distance_vec::distance_vec(std::string const &conf)
00102 : distance(conf)
00103 {
00104 set_function_type("distanceVec");
00105 enable(f_cvc_com_based);
00106 disable(f_cvc_explicit_gradient);
00107 x.type(colvarvalue::type_3vector);
00108 }
00109
00110
00111 colvar::distance_vec::distance_vec()
00112 : distance()
00113 {
00114 set_function_type("distanceVec");
00115 enable(f_cvc_com_based);
00116 disable(f_cvc_explicit_gradient);
00117 x.type(colvarvalue::type_3vector);
00118 }
00119
00120
00121 void colvar::distance_vec::calc_value()
00122 {
00123 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00124 x.rvector_value = group2->center_of_mass() - group1->center_of_mass();
00125 } else {
00126 x.rvector_value = cvm::position_distance(group1->center_of_mass(),
00127 group2->center_of_mass());
00128 }
00129 }
00130
00131
00132 void colvar::distance_vec::calc_gradients()
00133 {
00134
00135
00136 }
00137
00138
00139 void colvar::distance_vec::apply_force(colvarvalue const &force)
00140 {
00141 if (!group1->noforce)
00142 group1->apply_force(-1.0 * force.rvector_value);
00143
00144 if (!group2->noforce)
00145 group2->apply_force( force.rvector_value);
00146 }
00147
00148
00149 cvm::real colvar::distance_vec::dist2(colvarvalue const &x1,
00150 colvarvalue const &x2) const
00151 {
00152 return (cvm::position_distance(x1.rvector_value, x2.rvector_value)).norm2();
00153 }
00154
00155
00156 colvarvalue colvar::distance_vec::dist2_lgrad(colvarvalue const &x1,
00157 colvarvalue const &x2) const
00158 {
00159 return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value);
00160 }
00161
00162
00163 colvarvalue colvar::distance_vec::dist2_rgrad(colvarvalue const &x1,
00164 colvarvalue const &x2) const
00165 {
00166 return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value);
00167 }
00168
00169
00170
00171 colvar::distance_z::distance_z(std::string const &conf)
00172 : cvc(conf)
00173 {
00174 set_function_type("distanceZ");
00175 provide(f_cvc_inv_gradient);
00176 provide(f_cvc_Jacobian);
00177 enable(f_cvc_com_based);
00178 x.type(colvarvalue::type_scalar);
00179
00180
00181
00182 if (period != 0.0) {
00183 enable(f_cvc_periodic);
00184 }
00185
00186 if ((wrap_center != 0.0) && !is_enabled(f_cvc_periodic)) {
00187 cvm::error("Error: wrapAround was defined in a distanceZ component,"
00188 " but its period has not been set.\n");
00189 return;
00190 }
00191
00192 main = parse_group(conf, "main");
00193 ref1 = parse_group(conf, "ref");
00194
00195 ref2 = parse_group(conf, "ref2", true);
00196
00197 if ( ref2 ) {
00198 cvm::log("Using axis joining the centers of mass of groups \"ref\" and \"ref2\"\n");
00199 fixed_axis = false;
00200 if (key_lookup(conf, "axis"))
00201 cvm::log("Warning: explicit axis definition will be ignored!\n");
00202 } else {
00203 if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) {
00204 if (axis.norm2() == 0.0) {
00205 cvm::error("Axis vector is zero!");
00206 return;
00207 }
00208 if (axis.norm2() != 1.0) {
00209 axis = axis.unit();
00210 cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n");
00211 }
00212 }
00213 fixed_axis = true;
00214 }
00215
00216 init_total_force_params(conf);
00217
00218 }
00219
00220
00221 colvar::distance_z::distance_z()
00222 {
00223 set_function_type("distanceZ");
00224 provide(f_cvc_inv_gradient);
00225 provide(f_cvc_Jacobian);
00226 enable(f_cvc_com_based);
00227 x.type(colvarvalue::type_scalar);
00228 }
00229
00230
00231 void colvar::distance_z::calc_value()
00232 {
00233 if (fixed_axis) {
00234 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00235 dist_v = main->center_of_mass() - ref1->center_of_mass();
00236 } else {
00237 dist_v = cvm::position_distance(ref1->center_of_mass(),
00238 main->center_of_mass());
00239 }
00240 } else {
00241
00242 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00243 dist_v = main->center_of_mass() -
00244 (0.5 * (ref1->center_of_mass() + ref2->center_of_mass()));
00245 axis = ref2->center_of_mass() - ref1->center_of_mass();
00246 } else {
00247 dist_v = cvm::position_distance(0.5 * (ref1->center_of_mass() +
00248 ref2->center_of_mass()),
00249 main->center_of_mass());
00250 axis = cvm::position_distance(ref1->center_of_mass(),
00251 ref2->center_of_mass());
00252 }
00253 axis_norm = axis.norm();
00254 axis = axis.unit();
00255 }
00256 x.real_value = axis * dist_v;
00257 this->wrap(x);
00258 }
00259
00260
00261 void colvar::distance_z::calc_gradients()
00262 {
00263 main->set_weighted_gradient( axis );
00264
00265 if (fixed_axis) {
00266 ref1->set_weighted_gradient(-1.0 * axis);
00267 } else {
00268 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00269 ref1->set_weighted_gradient( 1.0 / axis_norm *
00270 (main->center_of_mass() - ref2->center_of_mass() -
00271 x.real_value * axis ));
00272 ref2->set_weighted_gradient( 1.0 / axis_norm *
00273 (ref1->center_of_mass() - main->center_of_mass() +
00274 x.real_value * axis ));
00275 } else {
00276 ref1->set_weighted_gradient( 1.0 / axis_norm * (
00277 cvm::position_distance(ref2->center_of_mass(),
00278 main->center_of_mass()) - x.real_value * axis ));
00279 ref2->set_weighted_gradient( 1.0 / axis_norm * (
00280 cvm::position_distance(main->center_of_mass(),
00281 ref1->center_of_mass()) + x.real_value * axis ));
00282 }
00283 }
00284 }
00285
00286
00287 void colvar::distance_z::calc_force_invgrads()
00288 {
00289 main->read_total_forces();
00290
00291 if (fixed_axis && !is_enabled(f_cvc_one_site_total_force)) {
00292 ref1->read_total_forces();
00293 ft.real_value = 0.5 * ((main->total_force() - ref1->total_force()) * axis);
00294 } else {
00295 ft.real_value = main->total_force() * axis;
00296 }
00297 }
00298
00299
00300 void colvar::distance_z::calc_Jacobian_derivative()
00301 {
00302 jd.real_value = 0.0;
00303 }
00304
00305
00306 void colvar::distance_z::apply_force(colvarvalue const &force)
00307 {
00308 if (!ref1->noforce)
00309 ref1->apply_colvar_force(force.real_value);
00310
00311 if (ref2 && !ref2->noforce)
00312 ref2->apply_colvar_force(force.real_value);
00313
00314 if (!main->noforce)
00315 main->apply_colvar_force(force.real_value);
00316 }
00317
00318
00319
00320 cvm::real colvar::distance_z::dist2(colvarvalue const &x1,
00321 colvarvalue const &x2) const
00322 {
00323 cvm::real diff = x1.real_value - x2.real_value;
00324 if (is_enabled(f_cvc_periodic)) {
00325 cvm::real shift = cvm::floor(diff/period + 0.5);
00326 diff -= shift * period;
00327 }
00328 return diff * diff;
00329 }
00330
00331
00332 colvarvalue colvar::distance_z::dist2_lgrad(colvarvalue const &x1,
00333 colvarvalue const &x2) const
00334 {
00335 cvm::real diff = x1.real_value - x2.real_value;
00336 if (is_enabled(f_cvc_periodic)) {
00337 cvm::real shift = cvm::floor(diff/period + 0.5);
00338 diff -= shift * period;
00339 }
00340 return 2.0 * diff;
00341 }
00342
00343
00344 colvarvalue colvar::distance_z::dist2_rgrad(colvarvalue const &x1,
00345 colvarvalue const &x2) const
00346 {
00347 cvm::real diff = x1.real_value - x2.real_value;
00348 if (is_enabled(f_cvc_periodic)) {
00349 cvm::real shift = cvm::floor(diff/period + 0.5);
00350 diff -= shift * period;
00351 }
00352 return (-2.0) * diff;
00353 }
00354
00355
00356 void colvar::distance_z::wrap(colvarvalue &x_unwrapped) const
00357 {
00358 if (!is_enabled(f_cvc_periodic)) {
00359
00360 return;
00361 }
00362 cvm::real shift =
00363 cvm::floor((x_unwrapped.real_value - wrap_center) / period + 0.5);
00364 x_unwrapped.real_value -= shift * period;
00365 }
00366
00367
00368
00369 colvar::distance_xy::distance_xy(std::string const &conf)
00370 : distance_z(conf)
00371 {
00372 set_function_type("distanceXY");
00373 init_as_distance();
00374
00375 provide(f_cvc_inv_gradient);
00376 provide(f_cvc_Jacobian);
00377 enable(f_cvc_com_based);
00378 }
00379
00380
00381 colvar::distance_xy::distance_xy()
00382 : distance_z()
00383 {
00384 set_function_type("distanceXY");
00385 init_as_distance();
00386
00387 provide(f_cvc_inv_gradient);
00388 provide(f_cvc_Jacobian);
00389 enable(f_cvc_com_based);
00390 }
00391
00392
00393 void colvar::distance_xy::calc_value()
00394 {
00395 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00396 dist_v = main->center_of_mass() - ref1->center_of_mass();
00397 } else {
00398 dist_v = cvm::position_distance(ref1->center_of_mass(),
00399 main->center_of_mass());
00400 }
00401 if (!fixed_axis) {
00402 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00403 v12 = ref2->center_of_mass() - ref1->center_of_mass();
00404 } else {
00405 v12 = cvm::position_distance(ref1->center_of_mass(),
00406 ref2->center_of_mass());
00407 }
00408 axis_norm = v12.norm();
00409 axis = v12.unit();
00410 }
00411
00412 dist_v_ortho = dist_v - (dist_v * axis) * axis;
00413 x.real_value = dist_v_ortho.norm();
00414 }
00415
00416
00417 void colvar::distance_xy::calc_gradients()
00418 {
00419
00420
00421 cvm::real A;
00422 cvm::real x_inv;
00423
00424 if (x.real_value == 0.0) return;
00425 x_inv = 1.0 / x.real_value;
00426
00427 if (fixed_axis) {
00428 ref1->set_weighted_gradient(-1.0 * x_inv * dist_v_ortho);
00429 main->set_weighted_gradient( x_inv * dist_v_ortho);
00430 } else {
00431 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00432 v13 = main->center_of_mass() - ref1->center_of_mass();
00433 } else {
00434 v13 = cvm::position_distance(ref1->center_of_mass(),
00435 main->center_of_mass());
00436 }
00437 A = (dist_v * axis) / axis_norm;
00438
00439 ref1->set_weighted_gradient( (A - 1.0) * x_inv * dist_v_ortho);
00440 ref2->set_weighted_gradient( -A * x_inv * dist_v_ortho);
00441 main->set_weighted_gradient( 1.0 * x_inv * dist_v_ortho);
00442 }
00443 }
00444
00445
00446 void colvar::distance_xy::calc_force_invgrads()
00447 {
00448 main->read_total_forces();
00449
00450 if (fixed_axis && !is_enabled(f_cvc_one_site_total_force)) {
00451 ref1->read_total_forces();
00452 ft.real_value = 0.5 / x.real_value * ((main->total_force() - ref1->total_force()) * dist_v_ortho);
00453 } else {
00454 ft.real_value = 1.0 / x.real_value * main->total_force() * dist_v_ortho;
00455 }
00456 }
00457
00458
00459 void colvar::distance_xy::calc_Jacobian_derivative()
00460 {
00461 jd.real_value = x.real_value ? (1.0 / x.real_value) : 0.0;
00462 }
00463
00464
00465 void colvar::distance_xy::apply_force(colvarvalue const &force)
00466 {
00467 if (!ref1->noforce)
00468 ref1->apply_colvar_force(force.real_value);
00469
00470 if (ref2 && !ref2->noforce)
00471 ref2->apply_colvar_force(force.real_value);
00472
00473 if (!main->noforce)
00474 main->apply_colvar_force(force.real_value);
00475 }
00476
00477
00478 simple_scalar_dist_functions(distance_xy)
00479
00480
00481
00482 colvar::distance_dir::distance_dir(std::string const &conf)
00483 : distance(conf)
00484 {
00485 set_function_type("distanceDir");
00486 enable(f_cvc_com_based);
00487 disable(f_cvc_explicit_gradient);
00488 x.type(colvarvalue::type_unit3vector);
00489 }
00490
00491
00492 colvar::distance_dir::distance_dir()
00493 : distance()
00494 {
00495 set_function_type("distanceDir");
00496 enable(f_cvc_com_based);
00497 disable(f_cvc_explicit_gradient);
00498 x.type(colvarvalue::type_unit3vector);
00499 }
00500
00501
00502 void colvar::distance_dir::calc_value()
00503 {
00504 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00505 dist_v = group2->center_of_mass() - group1->center_of_mass();
00506 } else {
00507 dist_v = cvm::position_distance(group1->center_of_mass(),
00508 group2->center_of_mass());
00509 }
00510 x.rvector_value = dist_v.unit();
00511 }
00512
00513
00514 void colvar::distance_dir::calc_gradients()
00515 {
00516
00517
00518
00519
00520
00521 }
00522
00523
00524 void colvar::distance_dir::apply_force(colvarvalue const &force)
00525 {
00526
00527 cvm::real const iprod = force.rvector_value * x.rvector_value;
00528 cvm::rvector const force_tang = force.rvector_value - iprod * x.rvector_value;
00529
00530 if (!group1->noforce)
00531 group1->apply_force(-1.0 * force_tang);
00532
00533 if (!group2->noforce)
00534 group2->apply_force( force_tang);
00535 }
00536
00537
00538 cvm::real colvar::distance_dir::dist2(colvarvalue const &x1,
00539 colvarvalue const &x2) const
00540 {
00541 return (x1.rvector_value - x2.rvector_value).norm2();
00542 }
00543
00544
00545 colvarvalue colvar::distance_dir::dist2_lgrad(colvarvalue const &x1,
00546 colvarvalue const &x2) const
00547 {
00548 return colvarvalue((x1.rvector_value - x2.rvector_value), colvarvalue::type_unit3vectorderiv);
00549 }
00550
00551
00552 colvarvalue colvar::distance_dir::dist2_rgrad(colvarvalue const &x1,
00553 colvarvalue const &x2) const
00554 {
00555 return colvarvalue((x2.rvector_value - x1.rvector_value), colvarvalue::type_unit3vectorderiv);
00556 }
00557
00558
00559
00560 colvar::distance_inv::distance_inv(std::string const &conf)
00561 : cvc(conf)
00562 {
00563 set_function_type("distanceInv");
00564 init_as_distance();
00565
00566 group1 = parse_group(conf, "group1");
00567 group2 = parse_group(conf, "group2");
00568
00569 get_keyval(conf, "exponent", exponent, 6);
00570 if (exponent%2) {
00571 cvm::error("Error: odd exponent provided, can only use even ones.\n");
00572 return;
00573 }
00574 if (exponent <= 0) {
00575 cvm::error("Error: negative or zero exponent provided.\n");
00576 return;
00577 }
00578
00579 for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
00580 for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
00581 if (ai1->id == ai2->id) {
00582 cvm::error("Error: group1 and group2 have some atoms in common: this is not allowed for distanceInv.\n");
00583 return;
00584 }
00585 }
00586 }
00587
00588 if (is_enabled(f_cvc_debug_gradient)) {
00589 cvm::log("Warning: debugGradients will not give correct results "
00590 "for distanceInv, because its value and gradients are computed "
00591 "simultaneously.\n");
00592 }
00593 }
00594
00595
00596 void colvar::distance_inv::calc_value()
00597 {
00598 x.real_value = 0.0;
00599 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00600 for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
00601 for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
00602 cvm::rvector const dv = ai2->pos - ai1->pos;
00603 cvm::real const d2 = dv.norm2();
00604 cvm::real const dinv = cvm::integer_power(d2, -1*(exponent/2));
00605 x.real_value += dinv;
00606 cvm::rvector const dsumddv = -1.0*(exponent/2) * dinv/d2 * 2.0 * dv;
00607 ai1->grad += -1.0 * dsumddv;
00608 ai2->grad += dsumddv;
00609 }
00610 }
00611 } else {
00612 for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
00613 for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
00614 cvm::rvector const dv = cvm::position_distance(ai1->pos, ai2->pos);
00615 cvm::real const d2 = dv.norm2();
00616 cvm::real const dinv = cvm::integer_power(d2, -1*(exponent/2));
00617 x.real_value += dinv;
00618 cvm::rvector const dsumddv = -1.0*(exponent/2) * dinv/d2 * 2.0 * dv;
00619 ai1->grad += -1.0 * dsumddv;
00620 ai2->grad += dsumddv;
00621 }
00622 }
00623 }
00624
00625 x.real_value *= 1.0 / cvm::real(group1->size() * group2->size());
00626 x.real_value = cvm::pow(x.real_value, -1.0/cvm::real(exponent));
00627
00628 cvm::real const dxdsum = (-1.0/(cvm::real(exponent))) *
00629 cvm::integer_power(x.real_value, exponent+1) /
00630 cvm::real(group1->size() * group2->size());
00631 for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) {
00632 ai1->grad *= dxdsum;
00633 }
00634 for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) {
00635 ai2->grad *= dxdsum;
00636 }
00637 }
00638
00639
00640 void colvar::distance_inv::calc_gradients()
00641 {
00642 }
00643
00644
00645 void colvar::distance_inv::apply_force(colvarvalue const &force)
00646 {
00647 if (!group1->noforce)
00648 group1->apply_colvar_force(force.real_value);
00649
00650 if (!group2->noforce)
00651 group2->apply_colvar_force(force.real_value);
00652 }
00653
00654
00655 simple_scalar_dist_functions(distance_inv)
00656
00657
00658
00659 colvar::distance_pairs::distance_pairs(std::string const &conf)
00660 : cvc(conf)
00661 {
00662 set_function_type("distancePairs");
00663
00664 group1 = parse_group(conf, "group1");
00665 group2 = parse_group(conf, "group2");
00666
00667 x.type(colvarvalue::type_vector);
00668 disable(f_cvc_explicit_gradient);
00669 x.vector1d_value.resize(group1->size() * group2->size());
00670 }
00671
00672
00673 colvar::distance_pairs::distance_pairs()
00674 {
00675 set_function_type("distancePairs");
00676 disable(f_cvc_explicit_gradient);
00677 x.type(colvarvalue::type_vector);
00678 }
00679
00680
00681 void colvar::distance_pairs::calc_value()
00682 {
00683 x.vector1d_value.resize(group1->size() * group2->size());
00684
00685 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00686 size_t i1, i2;
00687 for (i1 = 0; i1 < group1->size(); i1++) {
00688 for (i2 = 0; i2 < group2->size(); i2++) {
00689 cvm::rvector const dv = (*group2)[i2].pos - (*group1)[i1].pos;
00690 cvm::real const d = dv.norm();
00691 x.vector1d_value[i1*group2->size() + i2] = d;
00692 (*group1)[i1].grad = -1.0 * dv.unit();
00693 (*group2)[i2].grad = dv.unit();
00694 }
00695 }
00696 } else {
00697 size_t i1, i2;
00698 for (i1 = 0; i1 < group1->size(); i1++) {
00699 for (i2 = 0; i2 < group2->size(); i2++) {
00700 cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos,
00701 (*group2)[i2].pos);
00702 cvm::real const d = dv.norm();
00703 x.vector1d_value[i1*group2->size() + i2] = d;
00704 (*group1)[i1].grad = -1.0 * dv.unit();
00705 (*group2)[i2].grad = dv.unit();
00706 }
00707 }
00708 }
00709 }
00710
00711
00712 void colvar::distance_pairs::calc_gradients()
00713 {
00714
00715 }
00716
00717
00718 void colvar::distance_pairs::apply_force(colvarvalue const &force)
00719 {
00720 if (!is_enabled(f_cvc_pbc_minimum_image)) {
00721 size_t i1, i2;
00722 for (i1 = 0; i1 < group1->size(); i1++) {
00723 for (i2 = 0; i2 < group2->size(); i2++) {
00724 cvm::rvector const dv = (*group2)[i2].pos - (*group1)[i1].pos;
00725 (*group1)[i1].apply_force(force[i1*group2->size() + i2] * (-1.0) * dv.unit());
00726 (*group2)[i2].apply_force(force[i1*group2->size() + i2] * dv.unit());
00727 }
00728 }
00729 } else {
00730 size_t i1, i2;
00731 for (i1 = 0; i1 < group1->size(); i1++) {
00732 for (i2 = 0; i2 < group2->size(); i2++) {
00733 cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos,
00734 (*group2)[i2].pos);
00735 (*group1)[i1].apply_force(force[i1*group2->size() + i2] * (-1.0) * dv.unit());
00736 (*group2)[i2].apply_force(force[i1*group2->size() + i2] * dv.unit());
00737 }
00738 }
00739 }
00740 }
00741
00742
00743
00744 colvar::dipole_magnitude::dipole_magnitude(std::string const &conf)
00745 : cvc(conf)
00746 {
00747 set_function_type("dipoleMagnitude");
00748 atoms = parse_group(conf, "atoms");
00749 init_total_force_params(conf);
00750 x.type(colvarvalue::type_scalar);
00751 }
00752
00753
00754 colvar::dipole_magnitude::dipole_magnitude(cvm::atom const &a1)
00755 {
00756 set_function_type("dipoleMagnitude");
00757 atoms = new cvm::atom_group(std::vector<cvm::atom>(1, a1));
00758 register_atom_group(atoms);
00759 x.type(colvarvalue::type_scalar);
00760 }
00761
00762
00763 colvar::dipole_magnitude::dipole_magnitude()
00764 {
00765 set_function_type("dipoleMagnitude");
00766 x.type(colvarvalue::type_scalar);
00767 }
00768
00769
00770 void colvar::dipole_magnitude::calc_value()
00771 {
00772 cvm::atom_pos const atomsCom = atoms->center_of_mass();
00773 atoms->calc_dipole(atomsCom);
00774 dipoleV = atoms->dipole();
00775 x.real_value = dipoleV.norm();
00776 }
00777
00778
00779 void colvar::dipole_magnitude::calc_gradients()
00780 {
00781 cvm::real const aux1 = atoms->total_charge/atoms->total_mass;
00782 cvm::atom_pos const dipVunit = dipoleV.unit();
00783
00784 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00785 ai->grad = (ai->charge - aux1*ai->mass) * dipVunit;
00786 }
00787 }
00788
00789
00790 void colvar::dipole_magnitude::apply_force(colvarvalue const &force)
00791 {
00792 if (!atoms->noforce) {
00793 atoms->apply_colvar_force(force.real_value);
00794 }
00795 }
00796
00797
00798 simple_scalar_dist_functions(dipole_magnitude)
00799
00800
00801
00802 colvar::gyration::gyration(std::string const &conf)
00803 : cvc(conf)
00804 {
00805 set_function_type("gyration");
00806 init_as_distance();
00807
00808 provide(f_cvc_inv_gradient);
00809 provide(f_cvc_Jacobian);
00810 atoms = parse_group(conf, "atoms");
00811
00812 if (atoms->b_user_defined_fit) {
00813 cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".\n");
00814 } else {
00815 atoms->enable(f_ag_center);
00816 atoms->ref_pos.assign(1, cvm::atom_pos(0.0, 0.0, 0.0));
00817 atoms->fit_gradients.assign(atoms->size(), cvm::rvector(0.0, 0.0, 0.0));
00818 }
00819 }
00820
00821
00822 void colvar::gyration::calc_value()
00823 {
00824 x.real_value = 0.0;
00825 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00826 x.real_value += (ai->pos).norm2();
00827 }
00828 x.real_value = cvm::sqrt(x.real_value / cvm::real(atoms->size()));
00829 }
00830
00831
00832 void colvar::gyration::calc_gradients()
00833 {
00834 cvm::real const drdx = 1.0/(cvm::real(atoms->size()) * x.real_value);
00835 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00836 ai->grad = drdx * ai->pos;
00837 }
00838 }
00839
00840
00841 void colvar::gyration::calc_force_invgrads()
00842 {
00843 atoms->read_total_forces();
00844
00845 cvm::real const dxdr = 1.0/x.real_value;
00846 ft.real_value = 0.0;
00847
00848 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00849 ft.real_value += dxdr * ai->pos * ai->total_force;
00850 }
00851 }
00852
00853
00854 void colvar::gyration::calc_Jacobian_derivative()
00855 {
00856 jd = x.real_value ? (3.0 * cvm::real(atoms->size()) - 4.0) / x.real_value : 0.0;
00857 }
00858
00859
00860 void colvar::gyration::apply_force(colvarvalue const &force)
00861 {
00862 if (!atoms->noforce)
00863 atoms->apply_colvar_force(force.real_value);
00864 }
00865
00866
00867 simple_scalar_dist_functions(gyration)
00868
00869
00870
00871 colvar::inertia::inertia(std::string const &conf)
00872 : gyration(conf)
00873 {
00874 set_function_type("inertia");
00875 init_as_distance();
00876 }
00877
00878
00879 void colvar::inertia::calc_value()
00880 {
00881 x.real_value = 0.0;
00882 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00883 x.real_value += (ai->pos).norm2();
00884 }
00885 }
00886
00887
00888 void colvar::inertia::calc_gradients()
00889 {
00890 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00891 ai->grad = 2.0 * ai->pos;
00892 }
00893 }
00894
00895
00896 void colvar::inertia::apply_force(colvarvalue const &force)
00897 {
00898 if (!atoms->noforce)
00899 atoms->apply_colvar_force(force.real_value);
00900 }
00901
00902
00903 simple_scalar_dist_functions(inertia_z)
00904
00905
00906
00907 colvar::inertia_z::inertia_z(std::string const &conf)
00908 : inertia(conf)
00909 {
00910 set_function_type("inertiaZ");
00911 init_as_distance();
00912 if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) {
00913 if (axis.norm2() == 0.0) {
00914 cvm::error("Axis vector is zero!", COLVARS_INPUT_ERROR);
00915 return;
00916 }
00917 if (axis.norm2() != 1.0) {
00918 axis = axis.unit();
00919 cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n");
00920 }
00921 }
00922 }
00923
00924
00925 void colvar::inertia_z::calc_value()
00926 {
00927 x.real_value = 0.0;
00928 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00929 cvm::real const iprod = ai->pos * axis;
00930 x.real_value += iprod * iprod;
00931 }
00932 }
00933
00934
00935 void colvar::inertia_z::calc_gradients()
00936 {
00937 for (cvm::atom_iter ai = atoms->begin(); ai != atoms->end(); ai++) {
00938 ai->grad = 2.0 * (ai->pos * axis) * axis;
00939 }
00940 }
00941
00942
00943 void colvar::inertia_z::apply_force(colvarvalue const &force)
00944 {
00945 if (!atoms->noforce)
00946 atoms->apply_colvar_force(force.real_value);
00947 }
00948
00949
00950 simple_scalar_dist_functions(inertia)
00951
00952
00953
00954
00955 colvar::rmsd::rmsd(std::string const &conf)
00956 : cvc(conf)
00957 {
00958 set_function_type("rmsd");
00959 init_as_distance();
00960
00961 provide(f_cvc_inv_gradient);
00962
00963 atoms = parse_group(conf, "atoms");
00964
00965 if (!atoms || atoms->size() == 0) {
00966 cvm::error("Error: \"atoms\" must contain at least 1 atom to compute RMSD.");
00967 return;
00968 }
00969
00970 bool b_Jacobian_derivative = true;
00971 if (atoms->fitting_group != NULL && b_Jacobian_derivative) {
00972 cvm::log("The option \"fittingGroup\" (alternative group for fitting) was enabled: "
00973 "Jacobian derivatives of the RMSD will not be calculated.\n");
00974 b_Jacobian_derivative = false;
00975 }
00976 if (b_Jacobian_derivative) provide(f_cvc_Jacobian);
00977
00978
00979
00980
00981 if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) {
00982 cvm::log("Using reference positions from configuration file to calculate the variable.\n");
00983 if (ref_pos.size() != atoms->size()) {
00984 cvm::error("Error: the number of reference positions provided ("+
00985 cvm::to_str(ref_pos.size())+
00986 ") does not match the number of atoms of group \"atoms\" ("+
00987 cvm::to_str(atoms->size())+").\n");
00988 return;
00989 }
00990 } else {
00991 std::string ref_pos_file;
00992 if (get_keyval(conf, "refPositionsFile", ref_pos_file, std::string(""))) {
00993
00994 if (ref_pos.size()) {
00995 cvm::error("Error: cannot specify \"refPositionsFile\" and "
00996 "\"refPositions\" at the same time.\n");
00997 return;
00998 }
00999
01000 std::string ref_pos_col;
01001 double ref_pos_col_value=0.0;
01002
01003 if (get_keyval(conf, "refPositionsCol", ref_pos_col, std::string(""))) {
01004
01005 bool found = get_keyval(conf, "refPositionsColValue", ref_pos_col_value, 0.0);
01006 if (found && ref_pos_col_value==0.0) {
01007 cvm::error("Error: refPositionsColValue, "
01008 "if provided, must be non-zero.\n");
01009 return;
01010 }
01011 }
01012
01013 ref_pos.resize(atoms->size());
01014
01015 cvm::load_coords(ref_pos_file.c_str(), &ref_pos, atoms,
01016 ref_pos_col, ref_pos_col_value);
01017 } else {
01018 cvm::error("Error: no reference positions for RMSD; use either refPositions of refPositionsFile.");
01019 return;
01020 }
01021 }
01022
01023 if (ref_pos.size() != atoms->size()) {
01024 cvm::error("Error: found " + cvm::to_str(ref_pos.size()) +
01025 " reference positions for RMSD; expected " + cvm::to_str(atoms->size()));
01026 return;
01027 }
01028
01029 if (atoms->b_user_defined_fit) {
01030 cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".\n");
01031 } else {
01032
01033 cvm::log("Enabling \"centerToReference\" and \"rotateToReference\", to minimize RMSD before calculating it as a variable: "
01034 "if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n");
01035 atoms->enable(f_ag_center);
01036 atoms->enable(f_ag_rotate);
01037
01038
01039 atoms->ref_pos = ref_pos;
01040 atoms->center_ref_pos();
01041
01042 cvm::log("This is a standard minimum RMSD, derivatives of the optimal rotation "
01043 "will not be computed as they cancel out in the gradients.");
01044 atoms->disable(f_ag_fit_gradients);
01045
01046
01047 atoms->rot.request_group1_gradients(atoms->size());
01048
01049
01050 atoms->rot.request_group2_gradients(atoms->size());
01051 }
01052
01053 std::string perm_conf;
01054 size_t pos = 0;
01055 n_permutations = 1;
01056
01057 while (key_lookup(conf, "atomPermutation", &perm_conf, &pos)) {
01058 cvm::main()->cite_feature("Symmetry-adapted RMSD");
01059 std::vector<size_t> perm;
01060 if (perm_conf.size()) {
01061 std::istringstream is(perm_conf);
01062 size_t index;
01063 while (is >> index) {
01064 std::vector<int> const &ids = atoms->ids();
01065 size_t const ia = std::find(ids.begin(), ids.end(), index-1) - ids.begin();
01066 if (ia == atoms->size()) {
01067 cvm::error("Error: atom id " + cvm::to_str(index) +
01068 " is not a member of group \"atoms\".");
01069 return;
01070 }
01071 if (std::find(perm.begin(), perm.end(), ia) != perm.end()) {
01072 cvm::error("Error: atom id " + cvm::to_str(index) +
01073 " is mentioned more than once in atomPermutation list.");
01074 return;
01075 }
01076 perm.push_back(ia);
01077 }
01078 if (perm.size() != atoms->size()) {
01079 cvm::error("Error: symmetry permutation in input contains " + cvm::to_str(perm.size()) +
01080 " indices, but group \"atoms\" contains " + cvm::to_str(atoms->size()) + " atoms.");
01081 return;
01082 }
01083 cvm::log("atomPermutation = " + cvm::to_str(perm));
01084 n_permutations++;
01085
01086 for (size_t ia = 0; ia < atoms->size(); ia++) {
01087 ref_pos.push_back(ref_pos[perm[ia]]);
01088 }
01089 }
01090 }
01091 }
01092
01093
01094 void colvar::rmsd::calc_value()
01095 {
01096
01097
01098 x.real_value = 0.0;
01099 for (size_t ia = 0; ia < atoms->size(); ia++) {
01100 x.real_value += ((*atoms)[ia].pos - ref_pos[ia]).norm2();
01101 }
01102 best_perm_index = 0;
01103
01104
01105 size_t ref_pos_index = atoms->size();
01106 for (size_t ip = 1; ip < n_permutations; ip++) {
01107 cvm::real value = 0.0;
01108 for (size_t ia = 0; ia < atoms->size(); ia++) {
01109 value += ((*atoms)[ia].pos - ref_pos[ref_pos_index++]).norm2();
01110 }
01111 if (value < x.real_value) {
01112 x.real_value = value;
01113 best_perm_index = ip;
01114 }
01115 }
01116 x.real_value /= cvm::real(atoms->size());
01117 x.real_value = cvm::sqrt(x.real_value);
01118 }
01119
01120
01121 void colvar::rmsd::calc_gradients()
01122 {
01123 cvm::real const drmsddx2 = (x.real_value > 0.0) ?
01124 0.5 / (x.real_value * cvm::real(atoms->size())) :
01125 0.0;
01126
01127
01128 size_t const start = atoms->size() * best_perm_index;
01129 for (size_t ia = 0; ia < atoms->size(); ia++) {
01130 (*atoms)[ia].grad = (drmsddx2 * 2.0 * ((*atoms)[ia].pos - ref_pos[start + ia]));
01131 }
01132 }
01133
01134
01135 void colvar::rmsd::apply_force(colvarvalue const &force)
01136 {
01137 if (!atoms->noforce)
01138 atoms->apply_colvar_force(force.real_value);
01139 }
01140
01141
01142 void colvar::rmsd::calc_force_invgrads()
01143 {
01144 atoms->read_total_forces();
01145 ft.real_value = 0.0;
01146
01147
01148
01149 for (size_t ia = 0; ia < atoms->size(); ia++) {
01150 ft.real_value += (*atoms)[ia].grad * (*atoms)[ia].total_force;
01151 }
01152 ft.real_value *= atoms->size();
01153 }
01154
01155
01156 void colvar::rmsd::calc_Jacobian_derivative()
01157 {
01158
01159 cvm::real rotation_term = 0.0;
01160
01161
01162 if (atoms->is_enabled(f_ag_rotate)) {
01163
01164
01165 cvm::matrix2d<cvm::rvector> grad_rot_mat(3, 3);
01166
01167 cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
01168 for (size_t ia = 0; ia < atoms->size(); ia++) {
01169
01170
01171 cvm::vector1d<cvm::rvector> &dq = atoms->rot.dQ0_1[ia];
01172
01173 g11 = 2.0 * (atoms->rot.q)[1]*dq[1];
01174 g22 = 2.0 * (atoms->rot.q)[2]*dq[2];
01175 g33 = 2.0 * (atoms->rot.q)[3]*dq[3];
01176 g01 = (atoms->rot.q)[0]*dq[1] + (atoms->rot.q)[1]*dq[0];
01177 g02 = (atoms->rot.q)[0]*dq[2] + (atoms->rot.q)[2]*dq[0];
01178 g03 = (atoms->rot.q)[0]*dq[3] + (atoms->rot.q)[3]*dq[0];
01179 g12 = (atoms->rot.q)[1]*dq[2] + (atoms->rot.q)[2]*dq[1];
01180 g13 = (atoms->rot.q)[1]*dq[3] + (atoms->rot.q)[3]*dq[1];
01181 g23 = (atoms->rot.q)[2]*dq[3] + (atoms->rot.q)[3]*dq[2];
01182
01183
01184 grad_rot_mat[0][0] = -2.0 * (g22 + g33);
01185 grad_rot_mat[1][0] = 2.0 * (g12 + g03);
01186 grad_rot_mat[2][0] = 2.0 * (g13 - g02);
01187 grad_rot_mat[0][1] = 2.0 * (g12 - g03);
01188 grad_rot_mat[1][1] = -2.0 * (g11 + g33);
01189 grad_rot_mat[2][1] = 2.0 * (g01 + g23);
01190 grad_rot_mat[0][2] = 2.0 * (g02 + g13);
01191 grad_rot_mat[1][2] = 2.0 * (g23 - g01);
01192 grad_rot_mat[2][2] = -2.0 * (g11 + g22);
01193
01194 cvm::atom_pos &y = ref_pos[ia];
01195
01196 for (size_t alpha = 0; alpha < 3; alpha++) {
01197 for (size_t beta = 0; beta < 3; beta++) {
01198 rotation_term += grad_rot_mat[beta][alpha][alpha] * y[beta];
01199
01200
01201
01202 }
01203 }
01204 }
01205 }
01206
01207
01208 cvm::real translation_term = atoms->is_enabled(f_ag_center) ? 3.0 : 0.0;
01209
01210 jd.real_value = x.real_value > 0.0 ?
01211 (3.0 * atoms->size() - 1.0 - translation_term - rotation_term) / x.real_value :
01212 0.0;
01213 }
01214
01215
01216 simple_scalar_dist_functions(rmsd)
01217
01218
01219
01220 colvar::eigenvector::eigenvector(std::string const &conf)
01221 : cvc(conf)
01222 {
01223 set_function_type("eigenvector");
01224 provide(f_cvc_inv_gradient);
01225 provide(f_cvc_Jacobian);
01226 x.type(colvarvalue::type_scalar);
01227
01228 atoms = parse_group(conf, "atoms");
01229
01230 {
01231 bool const b_inline = get_keyval(conf, "refPositions", ref_pos, ref_pos);
01232
01233 if (b_inline) {
01234 cvm::log("Using reference positions from input file.\n");
01235 if (ref_pos.size() != atoms->size()) {
01236 cvm::error("Error: reference positions do not "
01237 "match the number of requested atoms.\n");
01238 return;
01239 }
01240 }
01241
01242 std::string file_name;
01243 if (get_keyval(conf, "refPositionsFile", file_name)) {
01244
01245 if (b_inline) {
01246 cvm::error("Error: refPositions and refPositionsFile cannot be specified at the same time.\n");
01247 return;
01248 }
01249
01250 std::string file_col;
01251 double file_col_value=0.0;
01252 if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) {
01253
01254 bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0);
01255 if (found && file_col_value==0.0) {
01256 cvm::error("Error: refPositionsColValue, "
01257 "if provided, must be non-zero.\n");
01258 return;
01259 }
01260 }
01261
01262 ref_pos.resize(atoms->size());
01263 cvm::load_coords(file_name.c_str(), &ref_pos, atoms,
01264 file_col, file_col_value);
01265 }
01266 }
01267
01268 if (ref_pos.size() == 0) {
01269 cvm::error("Error: reference positions were not provided.\n", COLVARS_INPUT_ERROR);
01270 return;
01271 }
01272
01273 if (ref_pos.size() != atoms->size()) {
01274 cvm::error("Error: reference positions do not "
01275 "match the number of requested atoms.\n", COLVARS_INPUT_ERROR);
01276 return;
01277 }
01278
01279
01280 cvm::rvector ref_pos_center(0.0, 0.0, 0.0);
01281 for (size_t i = 0; i < atoms->size(); i++) {
01282 ref_pos_center += ref_pos[i];
01283 }
01284 ref_pos_center *= 1.0 / atoms->size();
01285
01286 if (atoms->b_user_defined_fit) {
01287 cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".\n");
01288 } else {
01289
01290 cvm::log("Enabling \"centerToReference\" and \"rotateToReference\", to minimize RMSD before calculating the vector projection: "
01291 "if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n");
01292 atoms->enable(f_ag_center);
01293 atoms->enable(f_ag_rotate);
01294 atoms->ref_pos = ref_pos;
01295 atoms->center_ref_pos();
01296 atoms->disable(f_ag_fit_gradients);
01297
01298
01299
01300 atoms->rot.request_group1_gradients(atoms->size());
01301
01302
01303 atoms->rot.request_group2_gradients(atoms->size());
01304 }
01305
01306 {
01307 bool const b_inline = get_keyval(conf, "vector", eigenvec, eigenvec);
01308
01309 if (b_inline) {
01310 cvm::log("Using vector components from input file.\n");
01311 if (eigenvec.size() != atoms->size()) {
01312 cvm::error("Error: vector components do not "
01313 "match the number of requested atoms->\n");
01314 return;
01315 }
01316 }
01317
01318 std::string file_name;
01319 if (get_keyval(conf, "vectorFile", file_name)) {
01320
01321 if (b_inline) {
01322 cvm::error("Error: vector and vectorFile cannot be specified at the same time.\n");
01323 return;
01324 }
01325
01326 std::string file_col;
01327 double file_col_value=0.0;
01328 if (get_keyval(conf, "vectorCol", file_col, std::string(""))) {
01329
01330 bool found = get_keyval(conf, "vectorColValue", file_col_value, 0.0);
01331 if (found && file_col_value==0.0) {
01332 cvm::error("Error: vectorColValue, if provided, must be non-zero.\n");
01333 return;
01334 }
01335 }
01336
01337 eigenvec.resize(atoms->size());
01338 cvm::load_coords(file_name.c_str(), &eigenvec, atoms,
01339 file_col, file_col_value);
01340 }
01341 }
01342
01343 if (!ref_pos.size() || !eigenvec.size()) {
01344 cvm::error("Error: both reference coordinates"
01345 "and eigenvector must be defined.\n");
01346 return;
01347 }
01348
01349 cvm::atom_pos eig_center(0.0, 0.0, 0.0);
01350 for (size_t eil = 0; eil < atoms->size(); eil++) {
01351 eig_center += eigenvec[eil];
01352 }
01353 eig_center *= 1.0 / atoms->size();
01354 cvm::log("Geometric center of the provided vector: "+cvm::to_str(eig_center)+"\n");
01355
01356 bool b_difference_vector = false;
01357 get_keyval(conf, "differenceVector", b_difference_vector, false);
01358
01359 if (b_difference_vector) {
01360
01361 if (atoms->is_enabled(f_ag_center)) {
01362
01363 for (size_t i = 0; i < atoms->size(); i++) {
01364 eigenvec[i] -= eig_center;
01365 ref_pos[i] -= ref_pos_center;
01366 }
01367 }
01368 if (atoms->is_enabled(f_ag_rotate)) {
01369 atoms->rot.calc_optimal_rotation(eigenvec, ref_pos);
01370 for (size_t i = 0; i < atoms->size(); i++) {
01371 eigenvec[i] = atoms->rot.rotate(eigenvec[i]);
01372 }
01373 }
01374 cvm::log("\"differenceVector\" is on: subtracting the reference positions from the provided vector: v = x_vec - x_ref.\n");
01375 for (size_t i = 0; i < atoms->size(); i++) {
01376 eigenvec[i] -= ref_pos[i];
01377 }
01378 if (atoms->is_enabled(f_ag_center)) {
01379
01380 for (size_t i = 0; i < atoms->size(); i++) {
01381 ref_pos[i] += ref_pos_center;
01382 }
01383 }
01384
01385 } else {
01386 cvm::log("Centering the provided vector to zero.\n");
01387 for (size_t i = 0; i < atoms->size(); i++) {
01388 eigenvec[i] -= eig_center;
01389 }
01390 }
01391
01392
01393 eigenvec_invnorm2 = 0.0;
01394 for (size_t ein = 0; ein < atoms->size(); ein++) {
01395 eigenvec_invnorm2 += eigenvec[ein].norm2();
01396 }
01397 eigenvec_invnorm2 = 1.0 / eigenvec_invnorm2;
01398
01399
01400 bool normalize = false;
01401 get_keyval(conf, "normalizeVector", normalize, normalize);
01402
01403 if (normalize) {
01404 cvm::log("Normalizing the vector so that |v| = 1.\n");
01405 for (size_t i = 0; i < atoms->size(); i++) {
01406 eigenvec[i] *= cvm::sqrt(eigenvec_invnorm2);
01407 }
01408 eigenvec_invnorm2 = 1.0;
01409 } else if (b_difference_vector) {
01410 cvm::log("Normalizing the vector so that the norm of the projection |v ⋅ (x_vec - x_ref)| = 1.\n");
01411 for (size_t i = 0; i < atoms->size(); i++) {
01412 eigenvec[i] *= eigenvec_invnorm2;
01413 }
01414 eigenvec_invnorm2 = 1.0/eigenvec_invnorm2;
01415 } else {
01416 cvm::log("The norm of the vector is |v| = "+
01417 cvm::to_str(1.0/cvm::sqrt(eigenvec_invnorm2))+".\n");
01418 }
01419 }
01420
01421
01422 void colvar::eigenvector::calc_value()
01423 {
01424 x.real_value = 0.0;
01425 for (size_t i = 0; i < atoms->size(); i++) {
01426 x.real_value += ((*atoms)[i].pos - ref_pos[i]) * eigenvec[i];
01427 }
01428 }
01429
01430
01431 void colvar::eigenvector::calc_gradients()
01432 {
01433 for (size_t ia = 0; ia < atoms->size(); ia++) {
01434 (*atoms)[ia].grad = eigenvec[ia];
01435 }
01436 }
01437
01438
01439 void colvar::eigenvector::apply_force(colvarvalue const &force)
01440 {
01441 if (!atoms->noforce)
01442 atoms->apply_colvar_force(force.real_value);
01443 }
01444
01445
01446 void colvar::eigenvector::calc_force_invgrads()
01447 {
01448 atoms->read_total_forces();
01449 ft.real_value = 0.0;
01450
01451 for (size_t ia = 0; ia < atoms->size(); ia++) {
01452 ft.real_value += eigenvec_invnorm2 * (*atoms)[ia].grad *
01453 (*atoms)[ia].total_force;
01454 }
01455 }
01456
01457
01458 void colvar::eigenvector::calc_Jacobian_derivative()
01459 {
01460
01461 cvm::matrix2d<cvm::rvector> grad_rot_mat(3, 3);
01462 cvm::quaternion &quat0 = atoms->rot.q;
01463
01464
01465 cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23;
01466
01467 cvm::real sum = 0.0;
01468
01469 for (size_t ia = 0; ia < atoms->size(); ia++) {
01470
01471
01472
01473
01474 cvm::vector1d<cvm::rvector> &dq_1 = atoms->rot.dQ0_1[ia];
01475
01476 g11 = 2.0 * quat0[1]*dq_1[1];
01477 g22 = 2.0 * quat0[2]*dq_1[2];
01478 g33 = 2.0 * quat0[3]*dq_1[3];
01479 g01 = quat0[0]*dq_1[1] + quat0[1]*dq_1[0];
01480 g02 = quat0[0]*dq_1[2] + quat0[2]*dq_1[0];
01481 g03 = quat0[0]*dq_1[3] + quat0[3]*dq_1[0];
01482 g12 = quat0[1]*dq_1[2] + quat0[2]*dq_1[1];
01483 g13 = quat0[1]*dq_1[3] + quat0[3]*dq_1[1];
01484 g23 = quat0[2]*dq_1[3] + quat0[3]*dq_1[2];
01485
01486
01487
01488 grad_rot_mat[0][0] = -2.0 * (g22 + g33);
01489 grad_rot_mat[0][1] = 2.0 * (g12 + g03);
01490 grad_rot_mat[0][2] = 2.0 * (g13 - g02);
01491 grad_rot_mat[1][0] = 2.0 * (g12 - g03);
01492 grad_rot_mat[1][1] = -2.0 * (g11 + g33);
01493 grad_rot_mat[1][2] = 2.0 * (g01 + g23);
01494 grad_rot_mat[2][0] = 2.0 * (g02 + g13);
01495 grad_rot_mat[2][1] = 2.0 * (g23 - g01);
01496 grad_rot_mat[2][2] = -2.0 * (g11 + g22);
01497
01498 for (size_t i = 0; i < 3; i++) {
01499 for (size_t j = 0; j < 3; j++) {
01500 sum += grad_rot_mat[i][j][i] * eigenvec[ia][j];
01501 }
01502 }
01503 }
01504
01505 jd.real_value = sum * cvm::sqrt(eigenvec_invnorm2);
01506 }
01507
01508
01509 simple_scalar_dist_functions(eigenvector)
01510
01511
01512
01513 colvar::cartesian::cartesian(std::string const &conf)
01514 : cvc(conf)
01515 {
01516 set_function_type("cartesian");
01517
01518 atoms = parse_group(conf, "atoms");
01519
01520 bool use_x, use_y, use_z;
01521 get_keyval(conf, "useX", use_x, true);
01522 get_keyval(conf, "useY", use_y, true);
01523 get_keyval(conf, "useZ", use_z, true);
01524
01525 axes.clear();
01526 if (use_x) axes.push_back(0);
01527 if (use_y) axes.push_back(1);
01528 if (use_z) axes.push_back(2);
01529
01530 if (axes.size() == 0) {
01531 cvm::error("Error: a \"cartesian\" component was defined with all three axes disabled.\n");
01532 return;
01533 }
01534
01535 x.type(colvarvalue::type_vector);
01536 disable(f_cvc_explicit_gradient);
01537
01538 if (atoms != NULL) x.vector1d_value.resize(atoms->size() * axes.size());
01539 }
01540
01541
01542 void colvar::cartesian::calc_value()
01543 {
01544 size_t const dim = axes.size();
01545 size_t ia, j;
01546 for (ia = 0; ia < atoms->size(); ia++) {
01547 for (j = 0; j < dim; j++) {
01548 x.vector1d_value[dim*ia + j] = (*atoms)[ia].pos[axes[j]];
01549 }
01550 }
01551 }
01552
01553
01554 void colvar::cartesian::calc_gradients()
01555 {
01556
01557
01558
01559 }
01560
01561
01562 void colvar::cartesian::apply_force(colvarvalue const &force)
01563 {
01564 size_t const dim = axes.size();
01565 size_t ia, j;
01566 if (!atoms->noforce) {
01567 cvm::rvector f;
01568 for (ia = 0; ia < atoms->size(); ia++) {
01569 for (j = 0; j < dim; j++) {
01570 f[axes[j]] = force.vector1d_value[dim*ia + j];
01571 }
01572 (*atoms)[ia].apply_force(f);
01573 }
01574 }
01575 }