00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "colvarmodule.h"
00011 #include "colvarvalue.h"
00012 #include "colvarparse.h"
00013 #include "colvar.h"
00014 #include "colvarcomp.h"
00015
00016
00017
00018 colvar::orientation::orientation(std::string const &conf)
00019 : cvc()
00020 {
00021 set_function_type("orientation");
00022 disable(f_cvc_explicit_gradient);
00023 x.type(colvarvalue::type_quaternion);
00024 colvar::orientation::init(conf);
00025 }
00026
00027
00028 int colvar::orientation::init(std::string const &conf)
00029 {
00030 int error_code = cvc::init(conf);
00031
00032 atoms = parse_group(conf, "atoms");
00033 ref_pos.reserve(atoms->size());
00034
00035 if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) {
00036 cvm::log("Using reference positions from input file.\n");
00037 if (ref_pos.size() != atoms->size()) {
00038 return cvm::error("Error: reference positions do not "
00039 "match the number of requested atoms.\n", COLVARS_INPUT_ERROR);
00040 }
00041 }
00042
00043 {
00044 std::string file_name;
00045 if (get_keyval(conf, "refPositionsFile", file_name)) {
00046
00047 std::string file_col;
00048 double file_col_value=0.0;
00049 if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) {
00050
00051 bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0);
00052 if (found && file_col_value==0.0) {
00053 return cvm::error("Error: refPositionsColValue, "
00054 "if provided, must be non-zero.\n", COLVARS_INPUT_ERROR);
00055 }
00056 }
00057
00058 ref_pos.resize(atoms->size());
00059 cvm::load_coords(file_name.c_str(), &ref_pos, atoms,
00060 file_col, file_col_value);
00061 }
00062 }
00063
00064 if (!ref_pos.size()) {
00065 return cvm::error("Error: must define a set of "
00066 "reference coordinates.\n", COLVARS_INPUT_ERROR);
00067 }
00068
00069
00070 cvm::rvector ref_cog(0.0, 0.0, 0.0);
00071 size_t i;
00072 for (i = 0; i < ref_pos.size(); i++) {
00073 ref_cog += ref_pos[i];
00074 }
00075 ref_cog /= cvm::real(ref_pos.size());
00076 cvm::log("Centering the reference coordinates on the origin by subtracting "
00077 "the center of geometry at "+
00078 cvm::to_str(-1.0 * ref_cog)+"; it is "
00079 "assumed that each atom is the closest "
00080 "periodic image to the center of geometry.\n");
00081 for (i = 0; i < ref_pos.size(); i++) {
00082 ref_pos[i] -= ref_cog;
00083 }
00084
00085 get_keyval(conf, "closestToQuaternion", ref_quat, cvm::quaternion(1.0, 0.0, 0.0, 0.0));
00086
00087
00088 if (!atoms->noforce) {
00089 rot.request_group2_gradients(atoms->size());
00090 }
00091
00092 return error_code;
00093 }
00094
00095
00096 colvar::orientation::orientation()
00097 : cvc()
00098 {
00099 set_function_type("orientation");
00100 disable(f_cvc_explicit_gradient);
00101 x.type(colvarvalue::type_quaternion);
00102 }
00103
00104
00105 void colvar::orientation::calc_value()
00106 {
00107 rot.b_debug_gradients = is_enabled(f_cvc_debug_gradient);
00108 atoms_cog = atoms->center_of_geometry();
00109
00110 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00111
00112 if ((rot.q).inner(ref_quat) >= 0.0) {
00113 x.quaternion_value = rot.q;
00114 } else {
00115 x.quaternion_value = -1.0 * rot.q;
00116 }
00117 }
00118
00119
00120 void colvar::orientation::calc_gradients()
00121 {
00122
00123
00124
00125
00126 }
00127
00128
00129 void colvar::orientation::apply_force(colvarvalue const &force)
00130 {
00131 cvm::quaternion const &FQ = force.quaternion_value;
00132
00133 if (!atoms->noforce) {
00134 for (size_t ia = 0; ia < atoms->size(); ia++) {
00135 for (size_t i = 0; i < 4; i++) {
00136 (*atoms)[ia].apply_force(FQ[i] * rot.dQ0_2[ia][i]);
00137 }
00138 }
00139 }
00140 }
00141
00142
00143 cvm::real colvar::orientation::dist2(colvarvalue const &x1,
00144 colvarvalue const &x2) const
00145 {
00146 return x1.quaternion_value.dist2(x2);
00147 }
00148
00149
00150 colvarvalue colvar::orientation::dist2_lgrad(colvarvalue const &x1,
00151 colvarvalue const &x2) const
00152 {
00153 return x1.quaternion_value.dist2_grad(x2);
00154 }
00155
00156
00157 colvarvalue colvar::orientation::dist2_rgrad(colvarvalue const &x1,
00158 colvarvalue const &x2) const
00159 {
00160 return x2.quaternion_value.dist2_grad(x1);
00161 }
00162
00163
00164
00165 colvar::orientation_angle::orientation_angle(std::string const &conf)
00166 : orientation()
00167 {
00168 set_function_type("orientationAngle");
00169 init_as_angle();
00170 enable(f_cvc_explicit_gradient);
00171 orientation_angle::init(conf);
00172 }
00173
00174
00175 int colvar::orientation_angle::init(std::string const &conf)
00176 {
00177 return orientation::init(conf);
00178 }
00179
00180
00181 void colvar::orientation_angle::calc_value()
00182 {
00183 atoms_cog = atoms->center_of_geometry();
00184
00185 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00186
00187 if ((rot.q).q0 >= 0.0) {
00188 x.real_value = (180.0/PI) * 2.0 * cvm::acos((rot.q).q0);
00189 } else {
00190 x.real_value = (180.0/PI) * 2.0 * cvm::acos(-1.0 * (rot.q).q0);
00191 }
00192 }
00193
00194
00195 void colvar::orientation_angle::calc_gradients()
00196 {
00197 cvm::real const dxdq0 =
00198 ( ((rot.q).q0 * (rot.q).q0 < 1.0) ?
00199 ((180.0 / PI) * (-2.0) / cvm::sqrt(1.0 - ((rot.q).q0 * (rot.q).q0))) :
00200 0.0 );
00201
00202 for (size_t ia = 0; ia < atoms->size(); ia++) {
00203 (*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]);
00204 }
00205 }
00206
00207
00208 void colvar::orientation_angle::apply_force(colvarvalue const &force)
00209 {
00210 cvm::real const &fw = force.real_value;
00211 if (!atoms->noforce) {
00212 atoms->apply_colvar_force(fw);
00213 }
00214 }
00215
00216
00217 simple_scalar_dist_functions(orientation_angle)
00218
00219
00220
00221 colvar::orientation_proj::orientation_proj(std::string const &conf)
00222 : orientation()
00223 {
00224 set_function_type("orientationProj");
00225 enable(f_cvc_explicit_gradient);
00226 x.type(colvarvalue::type_scalar);
00227 init_scalar_boundaries(0.0, 1.0);
00228 orientation_proj::init(conf);
00229 }
00230
00231
00232 int colvar::orientation_proj::init(std::string const &conf)
00233 {
00234 return orientation::init(conf);
00235 }
00236
00237
00238 void colvar::orientation_proj::calc_value()
00239 {
00240 atoms_cog = atoms->center_of_geometry();
00241 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00242 x.real_value = 2.0 * (rot.q).q0 * (rot.q).q0 - 1.0;
00243 }
00244
00245
00246 void colvar::orientation_proj::calc_gradients()
00247 {
00248 cvm::real const dxdq0 = 2.0 * 2.0 * (rot.q).q0;
00249 for (size_t ia = 0; ia < atoms->size(); ia++) {
00250 (*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]);
00251 }
00252 }
00253
00254
00255 void colvar::orientation_proj::apply_force(colvarvalue const &force)
00256 {
00257 cvm::real const &fw = force.real_value;
00258
00259 if (!atoms->noforce) {
00260 atoms->apply_colvar_force(fw);
00261 }
00262 }
00263
00264
00265 simple_scalar_dist_functions(orientation_proj)
00266
00267
00268
00269 colvar::tilt::tilt(std::string const &conf)
00270 : orientation()
00271 {
00272 set_function_type("tilt");
00273 x.type(colvarvalue::type_scalar);
00274 enable(f_cvc_explicit_gradient);
00275 init_scalar_boundaries(-1.0, 1.0);
00276 tilt::init(conf);
00277 }
00278
00279
00280 int colvar::tilt::init(std::string const &conf)
00281 {
00282 int error_code = COLVARS_OK;
00283
00284 error_code |= orientation::init(conf);
00285
00286 get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0));
00287 if (axis.norm2() != 1.0) {
00288 axis /= axis.norm();
00289 cvm::log("Normalizing rotation axis to "+cvm::to_str(axis)+".\n");
00290 }
00291
00292 return error_code;
00293 }
00294
00295
00296 void colvar::tilt::calc_value()
00297 {
00298 atoms_cog = atoms->center_of_geometry();
00299
00300 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00301
00302 x.real_value = rot.cos_theta(axis);
00303 }
00304
00305
00306 void colvar::tilt::calc_gradients()
00307 {
00308 cvm::quaternion const dxdq = rot.dcos_theta_dq(axis);
00309
00310 for (size_t ia = 0; ia < atoms->size(); ia++) {
00311 (*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0);
00312 for (size_t iq = 0; iq < 4; iq++) {
00313 (*atoms)[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]);
00314 }
00315 }
00316 }
00317
00318
00319 void colvar::tilt::apply_force(colvarvalue const &force)
00320 {
00321 cvm::real const &fw = force.real_value;
00322
00323 if (!atoms->noforce) {
00324 atoms->apply_colvar_force(fw);
00325 }
00326 }
00327
00328
00329 simple_scalar_dist_functions(tilt)
00330
00331
00332
00333 colvar::spin_angle::spin_angle(std::string const &conf)
00334 : orientation()
00335 {
00336 set_function_type("spinAngle");
00337 init_as_periodic_angle();
00338 enable(f_cvc_periodic);
00339 enable(f_cvc_explicit_gradient);
00340 spin_angle::init(conf);
00341 }
00342
00343
00344 int colvar::spin_angle::init(std::string const &conf)
00345 {
00346 int error_code = COLVARS_OK;
00347
00348 error_code |= orientation::init(conf);
00349
00350 get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0));
00351 if (axis.norm2() != 1.0) {
00352 axis /= axis.norm();
00353 cvm::log("Normalizing rotation axis to "+cvm::to_str(axis)+".\n");
00354 }
00355
00356 return error_code;
00357 }
00358
00359
00360 colvar::spin_angle::spin_angle()
00361 : orientation()
00362 {
00363 set_function_type("spinAngle");
00364 period = 360.0;
00365 enable(f_cvc_periodic);
00366 enable(f_cvc_explicit_gradient);
00367 x.type(colvarvalue::type_scalar);
00368 }
00369
00370
00371 void colvar::spin_angle::calc_value()
00372 {
00373 atoms_cog = atoms->center_of_geometry();
00374
00375 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00376
00377 x.real_value = rot.spin_angle(axis);
00378 this->wrap(x);
00379 }
00380
00381
00382 void colvar::spin_angle::calc_gradients()
00383 {
00384 cvm::quaternion const dxdq = rot.dspin_angle_dq(axis);
00385
00386 for (size_t ia = 0; ia < atoms->size(); ia++) {
00387 (*atoms)[ia].grad = cvm::rvector(0.0, 0.0, 0.0);
00388 for (size_t iq = 0; iq < 4; iq++) {
00389 (*atoms)[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]);
00390 }
00391 }
00392 }
00393
00394
00395 void colvar::spin_angle::apply_force(colvarvalue const &force)
00396 {
00397 cvm::real const &fw = force.real_value;
00398
00399 if (!atoms->noforce) {
00400 atoms->apply_colvar_force(fw);
00401 }
00402 }
00403
00404
00405 cvm::real colvar::spin_angle::dist2(colvarvalue const &x1,
00406 colvarvalue const &x2) const
00407 {
00408 cvm::real diff = x1.real_value - x2.real_value;
00409 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00410 return diff * diff;
00411 }
00412
00413
00414 colvarvalue colvar::spin_angle::dist2_lgrad(colvarvalue const &x1,
00415 colvarvalue const &x2) const
00416 {
00417 cvm::real diff = x1.real_value - x2.real_value;
00418 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00419 return 2.0 * diff;
00420 }
00421
00422
00423 colvarvalue colvar::spin_angle::dist2_rgrad(colvarvalue const &x1,
00424 colvarvalue const &x2) const
00425 {
00426 cvm::real diff = x1.real_value - x2.real_value;
00427 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00428 return (-2.0) * diff;
00429 }
00430
00431
00432 void colvar::spin_angle::wrap(colvarvalue &x_unwrapped) const
00433 {
00434 if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
00435 x_unwrapped.real_value -= 360.0;
00436 return;
00437 }
00438
00439 if ((x_unwrapped.real_value - wrap_center) < -180.0) {
00440 x_unwrapped.real_value += 360.0;
00441 return;
00442 }
00443
00444 return;
00445 }
00446
00447
00448 colvar::euler_phi::euler_phi(std::string const &conf)
00449 : orientation()
00450 {
00451 set_function_type("eulerPhi");
00452 init_as_periodic_angle();
00453 enable(f_cvc_explicit_gradient);
00454 euler_phi::init(conf);
00455 }
00456
00457
00458 colvar::euler_phi::euler_phi()
00459 : orientation()
00460 {
00461 set_function_type("eulerPhi");
00462 init_as_periodic_angle();
00463 enable(f_cvc_explicit_gradient);
00464 }
00465
00466
00467 int colvar::euler_phi::init(std::string const &conf)
00468 {
00469 int error_code = COLVARS_OK;
00470 error_code |= orientation::init(conf);
00471 return error_code;
00472 }
00473
00474
00475 void colvar::euler_phi::calc_value()
00476 {
00477 atoms_cog = atoms->center_of_geometry();
00478
00479 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00480
00481 const cvm::real& q0 = rot.q.q0;
00482 const cvm::real& q1 = rot.q.q1;
00483 const cvm::real& q2 = rot.q.q2;
00484 const cvm::real& q3 = rot.q.q3;
00485 const cvm::real tmp_y = 2 * (q0 * q1 + q2 * q3);
00486 const cvm::real tmp_x = 1 - 2 * (q1 * q1 + q2 * q2);
00487 x.real_value = cvm::atan2(tmp_y, tmp_x) * (180.0/PI);
00488 }
00489
00490
00491 void colvar::euler_phi::calc_gradients()
00492 {
00493 const cvm::real& q0 = rot.q.q0;
00494 const cvm::real& q1 = rot.q.q1;
00495 const cvm::real& q2 = rot.q.q2;
00496 const cvm::real& q3 = rot.q.q3;
00497 const cvm::real denominator = (2 * q0 * q1 + 2 * q2 * q3) * (2 * q0 * q1 + 2 * q2 * q3) + (-2 * q1 * q1 - 2 * q2 * q2 + 1) * (-2 * q1 * q1 - 2 * q2 * q2 + 1);
00498 const cvm::real dxdq0 = (180.0/PI) * 2 * q1 * (-2 * q1 * q1 - 2 * q2 * q2 + 1) / denominator;
00499 const cvm::real dxdq1 = (180.0/PI) * (2 * q0 * (-2 * q1 * q1 - 2 * q2 * q2 + 1) - 4 * q1 * (-2 * q0 * q1 - 2 * q2 * q3)) / denominator;
00500 const cvm::real dxdq2 = (180.0/PI) * (-4 * q2 * (-2 * q0 * q1 - 2 * q2 * q3) + 2 * q3 * (-2 * q1 * q1 - 2 * q2 * q2 + 1)) / denominator;
00501 const cvm::real dxdq3 = (180.0/PI) * 2 * q2 * (-2 * q1 * q1 - 2 * q2 * q2 + 1) / denominator;
00502 for (size_t ia = 0; ia < atoms->size(); ia++) {
00503 (*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) +
00504 (dxdq1 * (rot.dQ0_2[ia])[1]) +
00505 (dxdq2 * (rot.dQ0_2[ia])[2]) +
00506 (dxdq3 * (rot.dQ0_2[ia])[3]);
00507 }
00508 }
00509
00510
00511 void colvar::euler_phi::apply_force(colvarvalue const &force)
00512 {
00513 cvm::real const &fw = force.real_value;
00514 if (!atoms->noforce) {
00515 atoms->apply_colvar_force(fw);
00516 }
00517 }
00518
00519
00520 cvm::real colvar::euler_phi::dist2(colvarvalue const &x1,
00521 colvarvalue const &x2) const
00522 {
00523 cvm::real diff = x1.real_value - x2.real_value;
00524 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00525 return diff * diff;
00526 }
00527
00528
00529 colvarvalue colvar::euler_phi::dist2_lgrad(colvarvalue const &x1,
00530 colvarvalue const &x2) const
00531 {
00532 cvm::real diff = x1.real_value - x2.real_value;
00533 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00534 return 2.0 * diff;
00535 }
00536
00537
00538 colvarvalue colvar::euler_phi::dist2_rgrad(colvarvalue const &x1,
00539 colvarvalue const &x2) const
00540 {
00541 cvm::real diff = x1.real_value - x2.real_value;
00542 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00543 return (-2.0) * diff;
00544 }
00545
00546
00547 void colvar::euler_phi::wrap(colvarvalue &x_unwrapped) const
00548 {
00549 if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
00550 x_unwrapped.real_value -= 360.0;
00551 return;
00552 }
00553
00554 if ((x_unwrapped.real_value - wrap_center) < -180.0) {
00555 x_unwrapped.real_value += 360.0;
00556 return;
00557 }
00558
00559 return;
00560 }
00561
00562
00563 colvar::euler_psi::euler_psi(std::string const &conf)
00564 : orientation()
00565 {
00566 set_function_type("eulerPsi");
00567 init_as_periodic_angle();
00568 enable(f_cvc_explicit_gradient);
00569 euler_psi::init(conf);
00570 }
00571
00572
00573 colvar::euler_psi::euler_psi()
00574 : orientation()
00575 {
00576 set_function_type("eulerPsi");
00577 init_as_periodic_angle();
00578 enable(f_cvc_explicit_gradient);
00579 }
00580
00581
00582 int colvar::euler_psi::init(std::string const &conf)
00583 {
00584 int error_code = COLVARS_OK;
00585 error_code |= orientation::init(conf);
00586 return error_code;
00587 }
00588
00589
00590 void colvar::euler_psi::calc_value()
00591 {
00592 atoms_cog = atoms->center_of_geometry();
00593
00594 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00595
00596 const cvm::real& q0 = rot.q.q0;
00597 const cvm::real& q1 = rot.q.q1;
00598 const cvm::real& q2 = rot.q.q2;
00599 const cvm::real& q3 = rot.q.q3;
00600 const cvm::real tmp_y = 2 * (q0 * q3 + q1 * q2);
00601 const cvm::real tmp_x = 1 - 2 * (q2 * q2 + q3 * q3);
00602 x.real_value = cvm::atan2(tmp_y, tmp_x) * (180.0/PI);
00603 }
00604
00605
00606 void colvar::euler_psi::calc_gradients()
00607 {
00608 const cvm::real& q0 = rot.q.q0;
00609 const cvm::real& q1 = rot.q.q1;
00610 const cvm::real& q2 = rot.q.q2;
00611 const cvm::real& q3 = rot.q.q3;
00612 const cvm::real denominator = (2 * q0 * q3 + 2 * q1 * q2) * (2 * q0 * q3 + 2 * q1 * q2) + (-2 * q2 * q2 - 2 * q3 * q3 + 1) * (-2 * q2 * q2 - 2 * q3 * q3 + 1);
00613 const cvm::real dxdq0 = (180.0/PI) * 2 * q3 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) / denominator;
00614 const cvm::real dxdq1 = (180.0/PI) * 2 * q2 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) / denominator;
00615 const cvm::real dxdq2 = (180.0/PI) * (2 * q1 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) - 4 * q2 * (-2 * q0 * q3 - 2 * q1 * q2)) / denominator;
00616 const cvm::real dxdq3 = (180.0/PI) * (2 * q0 * (-2 * q2 * q2 - 2 * q3 * q3 + 1) - 4 * q3 * (-2 * q0 * q3 - 2 * q1 * q2)) / denominator;
00617 for (size_t ia = 0; ia < atoms->size(); ia++) {
00618 (*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) +
00619 (dxdq1 * (rot.dQ0_2[ia])[1]) +
00620 (dxdq2 * (rot.dQ0_2[ia])[2]) +
00621 (dxdq3 * (rot.dQ0_2[ia])[3]);
00622 }
00623 }
00624
00625
00626 void colvar::euler_psi::apply_force(colvarvalue const &force)
00627 {
00628 cvm::real const &fw = force.real_value;
00629 if (!atoms->noforce) {
00630 atoms->apply_colvar_force(fw);
00631 }
00632 }
00633
00634
00635 cvm::real colvar::euler_psi::dist2(colvarvalue const &x1,
00636 colvarvalue const &x2) const
00637 {
00638 cvm::real diff = x1.real_value - x2.real_value;
00639 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00640 return diff * diff;
00641 }
00642
00643
00644 colvarvalue colvar::euler_psi::dist2_lgrad(colvarvalue const &x1,
00645 colvarvalue const &x2) const
00646 {
00647 cvm::real diff = x1.real_value - x2.real_value;
00648 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00649 return 2.0 * diff;
00650 }
00651
00652
00653 colvarvalue colvar::euler_psi::dist2_rgrad(colvarvalue const &x1,
00654 colvarvalue const &x2) const
00655 {
00656 cvm::real diff = x1.real_value - x2.real_value;
00657 diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff));
00658 return (-2.0) * diff;
00659 }
00660
00661
00662 void colvar::euler_psi::wrap(colvarvalue &x_unwrapped) const
00663 {
00664 if ((x_unwrapped.real_value - wrap_center) >= 180.0) {
00665 x_unwrapped.real_value -= 360.0;
00666 return;
00667 }
00668
00669 if ((x_unwrapped.real_value - wrap_center) < -180.0) {
00670 x_unwrapped.real_value += 360.0;
00671 return;
00672 }
00673
00674 return;
00675 }
00676
00677
00678 colvar::euler_theta::euler_theta(std::string const &conf)
00679 : orientation()
00680 {
00681 set_function_type("eulerTheta");
00682 init_as_angle();
00683 enable(f_cvc_explicit_gradient);
00684 euler_theta::init(conf);
00685 }
00686
00687
00688 colvar::euler_theta::euler_theta()
00689 : orientation()
00690 {
00691 set_function_type("eulerTheta");
00692 init_as_angle();
00693 enable(f_cvc_explicit_gradient);
00694 }
00695
00696
00697 int colvar::euler_theta::init(std::string const &conf)
00698 {
00699 int error_code = COLVARS_OK;
00700 error_code |= orientation::init(conf);
00701 return error_code;
00702 }
00703
00704
00705 void colvar::euler_theta::calc_value()
00706 {
00707 atoms_cog = atoms->center_of_geometry();
00708
00709 rot.calc_optimal_rotation(ref_pos, atoms->positions_shifted(-1.0 * atoms_cog));
00710
00711 const cvm::real& q0 = rot.q.q0;
00712 const cvm::real& q1 = rot.q.q1;
00713 const cvm::real& q2 = rot.q.q2;
00714 const cvm::real& q3 = rot.q.q3;
00715 x.real_value = cvm::asin(2 * (q0 * q2 - q3 * q1)) * (180.0/PI);
00716 }
00717
00718
00719 void colvar::euler_theta::calc_gradients()
00720 {
00721 const cvm::real& q0 = rot.q.q0;
00722 const cvm::real& q1 = rot.q.q1;
00723 const cvm::real& q2 = rot.q.q2;
00724 const cvm::real& q3 = rot.q.q3;
00725 const cvm::real denominator = cvm::sqrt(1 - (2 * q0 * q2 - 2 * q1 * q3) * (2 * q0 * q2 - 2 * q1 * q3));
00726 const cvm::real dxdq0 = (180.0/PI) * 2 * q2 / denominator;
00727 const cvm::real dxdq1 = (180.0/PI) * -2 * q3 / denominator;
00728 const cvm::real dxdq2 = (180.0/PI) * 2 * q0 / denominator;
00729 const cvm::real dxdq3 = (180.0/PI) * -2 * q1 / denominator;
00730 for (size_t ia = 0; ia < atoms->size(); ia++) {
00731 (*atoms)[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]) +
00732 (dxdq1 * (rot.dQ0_2[ia])[1]) +
00733 (dxdq2 * (rot.dQ0_2[ia])[2]) +
00734 (dxdq3 * (rot.dQ0_2[ia])[3]);
00735 }
00736 }
00737
00738
00739 void colvar::euler_theta::apply_force(colvarvalue const &force)
00740 {
00741 cvm::real const &fw = force.real_value;
00742 if (!atoms->noforce) {
00743 atoms->apply_colvar_force(fw);
00744 }
00745 }
00746
00747
00748 cvm::real colvar::euler_theta::dist2(colvarvalue const &x1,
00749 colvarvalue const &x2) const
00750 {
00751
00752 return cvc::dist2(x1, x2);
00753 }
00754
00755
00756 colvarvalue colvar::euler_theta::dist2_lgrad(colvarvalue const &x1,
00757 colvarvalue const &x2) const
00758 {
00759
00760 return cvc::dist2_lgrad(x1, x2);
00761 }
00762
00763
00764 colvarvalue colvar::euler_theta::dist2_rgrad(colvarvalue const &x1,
00765 colvarvalue const &x2) const
00766 {
00767
00768 return cvc::dist2_rgrad(x1, x2);
00769 }