00001 #include "colvarmodule.h"
00002 #include "colvarparse.h"
00003 #include "colvaratoms.h"
00004
00005
00006
00007
00008
00009
00010
00011
00012 cvm::atom_group::atom_group (std::string const &conf,
00013 char const *key,
00014 atom_group *ref_pos_group_in)
00015 : b_center (false), b_rotate (false),
00016 ref_pos_group (NULL),
00017
00018 noforce (false)
00019 {
00020 cvm::log ("Defining atom group \""+
00021 std::string (key)+"\".\n");
00022 parse (conf, key, ref_pos_group_in);
00023 }
00024
00025
00026 void cvm::atom_group::parse (std::string const &conf,
00027 char const *key,
00028 atom_group *ref_pos_group_in)
00029 {
00030 std::string group_conf;
00031
00032
00033
00034
00035 save_delimiters = false;
00036 key_lookup (conf, key, group_conf, dummy_pos);
00037
00038
00039 save_delimiters = true;
00040
00041 if (group_conf.size() == 0) {
00042 cvm::fatal_error ("Error: atom group \""+
00043 std::string (key)+"\" is set, but "
00044 "has no definition.\n");
00045 }
00046
00047 cvm::increase_depth();
00048
00049 cvm::log ("Initializing atom group \""+std::string (key)+"\".\n");
00050
00051
00052 colvarparse::Parse_Mode mode = parse_silent;
00053 {
00054 bool b_verbose;
00055 get_keyval (group_conf, "verboseOutput", b_verbose, false, parse_silent);
00056 if (b_verbose) mode = parse_normal;
00057 }
00058
00059 {
00060
00061 std::vector<int> atom_indexes;
00062 if (get_keyval (group_conf, "atomNumbers", atom_indexes, atom_indexes, mode)) {
00063 if (atom_indexes.size()) {
00064 this->reserve (this->size()+atom_indexes.size());
00065 for (size_t i = 0; i < atom_indexes.size(); i++) {
00066 this->push_back (cvm::atom (atom_indexes[i]));
00067 }
00068 } else
00069 cvm::fatal_error ("Error: no numbers provided for \""
00070 "atom_numbers\".\n");
00071 }
00072 }
00073
00074 {
00075 std::string range_conf = "";
00076 size_t pos = 0;
00077 while (key_lookup (group_conf, "atomNumbersRange",
00078 range_conf, pos)) {
00079
00080 if (range_conf.size()) {
00081 std::istringstream is (range_conf);
00082 int initial, final;
00083 char dash;
00084 if ( (is >> initial) && (initial > 0) &&
00085 (is >> dash) && (dash == '-') &&
00086 (is >> final) && (final > 0) ) {
00087 for (int anum = initial; anum <= final; anum++) {
00088 this->push_back (cvm::atom (anum));
00089 }
00090 range_conf = "";
00091 continue;
00092 }
00093 }
00094
00095 cvm::fatal_error ("Error: no valid definition for \""
00096 "atom_numbers_range\", \""+
00097 range_conf+"\".\n");
00098 }
00099 }
00100
00101 std::vector<std::string> psf_segids;
00102 get_keyval (group_conf, "psfSegID", psf_segids, std::vector<std::string> (1, std::string("MAIN")), mode);
00103 for (std::vector<std::string>::iterator psii = psf_segids.begin();
00104 psii < psf_segids.end(); psii++) {
00105
00106 if ( (psii->size() == 0) || (psii->size() > 4) ) {
00107 cvm::fatal_error ("Error: invalid segmend identifier provided, \""+
00108 (*psii)+"\".\n");
00109 }
00110 }
00111
00112 {
00113 std::string range_conf = "";
00114 size_t pos = 0;
00115 size_t range_count = 0;
00116 std::vector<std::string>::iterator psii = psf_segids.begin();
00117 while (key_lookup (group_conf, "atomNameResidueRange",
00118 range_conf, pos)) {
00119
00120 if (psii > psf_segids.end()) {
00121 cvm::fatal_error ("Error: more instances of \"atomNameResidueRange\" than "
00122 "values of \"psfSegID\".\n");
00123 }
00124
00125 std::string const &psf_segid = *psii;
00126
00127 if (range_conf.size()) {
00128
00129 std::istringstream is (range_conf);
00130 std::string atom_name;
00131 int initial, final;
00132 char dash;
00133 if ( (is >> atom_name) && (atom_name.size()) &&
00134 (is >> initial) && (initial > 0) &&
00135 (is >> dash) && (dash == '-') &&
00136 (is >> final) && (final > 0) ) {
00137 for (int resid = initial; resid <= final; resid++) {
00138 this->push_back (cvm::atom (resid, atom_name, psf_segid));
00139 }
00140 range_conf = "";
00141 continue;
00142 }
00143
00144 } else {
00145 cvm::fatal_error ("Error: no valid definition for \""
00146 "atom_name_residue_range\", \""+
00147 range_conf+"\".\n");
00148 }
00149
00150 psii++;
00151 }
00152 }
00153
00154 {
00155
00156 std::string atoms_file_name;
00157 if (get_keyval (group_conf, "atomsFile", atoms_file_name, std::string (""), mode)) {
00158
00159 std::string atoms_col;
00160 get_keyval (group_conf, "atomsCol", atoms_col, std::string ("O"), mode);
00161
00162 double atoms_col_value;
00163 bool const atoms_col_value_defined = get_keyval (group_conf, "atomsColValue", atoms_col_value, 0.0, mode);
00164 if (atoms_col_value_defined && (!atoms_col_value))
00165 cvm::fatal_error ("Error: atomsColValue, "
00166 "if provided, must be non-zero.\n");
00167
00168 cvm::load_atoms (atoms_file_name.c_str(), *this, atoms_col, atoms_col_value);
00169 }
00170 }
00171
00172 for (std::vector<cvm::atom>::iterator a1 = this->begin();
00173 a1 != this->end(); a1++) {
00174 std::vector<cvm::atom>::iterator a2 = a1;
00175 ++a2;
00176 for ( ; a2 != this->end(); a2++) {
00177 if (a1->id == a2->id) {
00178 if (cvm::debug())
00179 cvm::log ("Discarding doubly counted atom with number "+
00180 cvm::to_str (a1->id+1)+".\n");
00181 a2 = this->erase (a2);
00182 if (a2 == this->end())
00183 break;
00184 }
00185 }
00186 }
00187
00188 if (get_keyval (group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos(), mode)) {
00189 b_dummy = true;
00190 this->total_mass = 1.0;
00191 } else
00192 b_dummy = false;
00193
00194 if (b_dummy && (this->size()))
00195 cvm::fatal_error ("Error: cannot set up group \""+
00196 std::string (key)+"\" as a dummy atom "
00197 "and provide it with atom definitions.\n");
00198
00199 #if (! defined (COLVARS_STANDALONE))
00200 if ( (!b_dummy) && (!cvm::b_analysis) && (!(this->size())) ) {
00201 cvm::fatal_error ("Error: no atoms defined for atom group \""+
00202 std::string (key)+"\".\n");
00203 }
00204 #endif
00205
00206 if (!b_dummy) {
00207 this->total_mass = 0.0;
00208 for (cvm::atom_iter ai = this->begin();
00209 ai != this->end(); ai++) {
00210 this->total_mass += ai->mass;
00211 }
00212 }
00213
00214 get_keyval (group_conf, "disableForces", noforce, false, mode);
00215
00216 get_keyval (group_conf, "centerReference", b_center, false, mode);
00217 get_keyval (group_conf, "rotateReference", b_rotate, false, mode);
00218
00219 if (b_center || b_rotate) {
00220
00221 if (b_dummy)
00222 cvm::fatal_error ("Error: cannot set \"centerReference\" or "
00223 "\"rotateReference\" with \"dummyAtom\".\n");
00224
00225
00226
00227 if (key_lookup (group_conf, "refPositionsGroup")) {
00228 if (ref_pos_group) {
00229 cvm::fatal_error ("Error: the atom group \""+
00230 std::string (key)+"\" has already a reference group "
00231 "for the rototranslational fit, which was communicated by the "
00232 "colvar component. You should not use refPositionsGroup "
00233 "in this case.\n");
00234 }
00235 cvm::log ("Within atom group \""+std::string (key)+"\":\n");
00236 ref_pos_group = new atom_group (group_conf, "refPositionsGroup");
00237 }
00238
00239 if (get_keyval (group_conf, "refPositions", ref_pos, ref_pos, mode)) {
00240 cvm::log ("Using reference positions from input file.\n");
00241 atom_group *ag = ref_pos_group ? ref_pos_group : this;
00242 if (ref_pos.size() != ag->size()) {
00243 cvm::fatal_error ("Error: the number of reference positions provided ("+
00244 cvm::to_str (ref_pos.size())+
00245 ") does not match the number of atoms within \""+
00246 std::string (key)+
00247 "\" ("+cvm::to_str (ag->size())+").\n");
00248 }
00249 }
00250
00251 std::string ref_pos_file;
00252 if (get_keyval (group_conf, "refPositionsFile", ref_pos_file, std::string (""), mode)) {
00253
00254 if (ref_pos.size()) {
00255 cvm::fatal_error ("Error: cannot specify \"refPositionsFile\" and "
00256 "\"refPositions\" at the same time.\n");
00257 }
00258
00259 std::string ref_pos_col;
00260 get_keyval (group_conf, "refPositionsCol", ref_pos_col, std::string ("O"), mode);
00261
00262 double ref_pos_col_value;
00263 bool found = get_keyval (group_conf, "refPositionsColValue", ref_pos_col_value, 0.0, mode);
00264 if (found && !ref_pos_col_value)
00265 cvm::fatal_error ("Error: refPositionsColValue, "
00266 "if provided, must be non-zero.\n");
00267
00268 cvm::load_coords (ref_pos_file.c_str(), ref_pos,
00269 ref_pos_col, ref_pos_col_value);
00270 }
00271
00272 if (ref_pos.size()) {
00273
00274 if (b_rotate) {
00275 atom_group *ag = ref_pos_group ? ref_pos_group : this;
00276 if (ref_pos.size() != ag->size())
00277 cvm::fatal_error ("Error: the number of reference positions provided ("+
00278 cvm::to_str (ref_pos.size())+
00279 ") does not match the number of atoms within \""+
00280 std::string (key)+
00281 "\" ("+cvm::to_str (ag->size())+").\n");
00282 }
00283
00284
00285
00286
00287 ref_pos_com = cvm::atom_pos (0.0, 0.0, 0.0);
00288
00289 atom_group *ag = ref_pos_group ? ref_pos_group : this;
00290
00291 cvm::atom_iter ai = ag->begin();
00292 std::vector<cvm::atom_pos>::iterator pi = ref_pos.begin();
00293 for ( ; ai != ag->end(); pi++, ai++) {
00294 ref_pos_com += ai->mass * (*pi);
00295 }
00296 ref_pos_com /= ag->total_mass;
00297
00298 for (std::vector<cvm::atom_pos>::iterator pi = ref_pos.begin();
00299 pi != ref_pos.end(); pi++) {
00300 (*pi) -= ref_pos_com;
00301 }
00302 } else {
00303 #if (! defined (COLVARS_STANDALONE))
00304 if (!cvm::b_analysis)
00305 cvm::fatal_error ("Error: no reference positions provided.\n");
00306 #endif
00307 }
00308
00309 if (b_rotate && !noforce) {
00310 cvm::log ("Warning: atom group \""+std::string (key)+
00311 "\" is set to be rotated to a reference orientation: "
00312 "a torque different than zero on this group "
00313 "could make the simulation unstable. "
00314 "If this happens, set \"disableForces\" to yes "
00315 "for this group.\n");
00316 }
00317
00318 }
00319
00320
00321 if (cvm::debug())
00322 cvm::log ("Done initializing atom group with name \""+
00323 std::string (key)+"\".\n");
00324
00325 this->check_keywords (group_conf, key);
00326
00327 cvm::log ("Atom group \""+std::string (key)+"\" defined, "+
00328 cvm::to_str (this->size())+" initialized: total mass = "+
00329 cvm::to_str (this->total_mass)+".\n");
00330
00331 cvm::decrease_depth();
00332 }
00333
00334
00335 cvm::atom_group::atom_group (std::vector<cvm::atom> const &atoms)
00336 : b_dummy (false), b_center (false), b_rotate (false),
00337 ref_pos_group (NULL), noforce (false)
00338 {
00339 this->reserve (atoms.size());
00340 for (size_t i = 0; i < atoms.size(); i++) {
00341 this->push_back (atoms[i]);
00342 }
00343 total_mass = 0.0;
00344 for (cvm::atom_iter ai = this->begin();
00345 ai != this->end(); ai++) {
00346 total_mass += ai->mass;
00347 }
00348 }
00349
00350
00351 cvm::atom_group::atom_group()
00352 : b_center (false), b_rotate (false),
00353 ref_pos_group (NULL), noforce (false)
00354 {
00355 total_mass = 0.0;
00356 }
00357
00358
00359 cvm::atom_group::~atom_group()
00360 {
00361 if (ref_pos_group) {
00362 delete ref_pos_group;
00363 ref_pos_group = NULL;
00364 }
00365 }
00366
00367
00368 void cvm::atom_group::add_atom (cvm::atom const &a)
00369 {
00370 if (b_dummy) {
00371 cvm::fatal_error ("Error: cannot add atoms to a dummy group.\n");
00372 } else {
00373 this->push_back (a);
00374 total_mass += a.mass;
00375 }
00376 }
00377
00378
00379 void cvm::atom_group::read_positions()
00380 {
00381 if (b_dummy) return;
00382
00383 #if (! defined (COLVARS_STANDALONE))
00384 if (!this->size())
00385 cvm::fatal_error ("Error: no atoms defined in the requested group.\n");
00386 #endif
00387
00388 for (cvm::atom_iter ai = this->begin();
00389 ai != this->end(); ai++) {
00390 ai->read_position();
00391 }
00392
00393 if (ref_pos_group)
00394 ref_pos_group->read_positions();
00395
00396 atom_group *fit_group = ref_pos_group ? ref_pos_group : this;
00397
00398 if (b_center) {
00399
00400
00401
00402 cvm::atom_pos const com = fit_group->center_of_mass();
00403 for (cvm::atom_iter ai = this->begin();
00404 ai != this->end(); ai++) {
00405 ai->pos -= com;
00406 }
00407 }
00408
00409 if (b_rotate) {
00410
00411
00412
00413
00414 rot.calc_optimal_rotation (fit_group->positions(), ref_pos);
00415
00416 for (cvm::atom_iter ai = this->begin();
00417 ai != this->end(); ai++) {
00418 ai->pos = rot.rotate (ai->pos);
00419 }
00420 }
00421
00422 if (b_center) {
00423
00424 for (cvm::atom_iter ai = this->begin();
00425 ai != this->end(); ai++) {
00426 ai->pos += ref_pos_com;
00427 }
00428 }
00429 }
00430
00431
00432 void cvm::atom_group::apply_translation (cvm::rvector const &t)
00433 {
00434 if (b_dummy) return;
00435
00436 for (cvm::atom_iter ai = this->begin();
00437 ai != this->end(); ai++) {
00438 ai->pos += t;
00439 }
00440 }
00441
00442
00443 void cvm::atom_group::apply_rotation (cvm::rotation const &rot)
00444 {
00445 if (b_dummy) return;
00446
00447 for (cvm::atom_iter ai = this->begin();
00448 ai != this->end(); ai++) {
00449 ai->pos = rot.rotate (ai->pos);
00450 }
00451 }
00452
00453
00454 void cvm::atom_group::read_velocities()
00455 {
00456 if (b_dummy) return;
00457
00458 if (b_rotate) {
00459
00460 for (cvm::atom_iter ai = this->begin();
00461 ai != this->end(); ai++) {
00462 ai->read_velocity();
00463 ai->vel = rot.rotate (ai->vel);
00464 }
00465
00466 } else {
00467
00468 for (cvm::atom_iter ai = this->begin();
00469 ai != this->end(); ai++) {
00470 ai->read_velocity();
00471 }
00472 }
00473 }
00474
00475 void cvm::atom_group::read_system_forces()
00476 {
00477 if (b_dummy) return;
00478
00479 if (b_rotate) {
00480
00481 for (cvm::atom_iter ai = this->begin();
00482 ai != this->end(); ai++) {
00483 ai->read_system_force();
00484 ai->system_force = rot.rotate (ai->system_force);
00485 }
00486
00487 } else {
00488
00489 for (cvm::atom_iter ai = this->begin();
00490 ai != this->end(); ai++) {
00491 ai->read_system_force();
00492 }
00493 }
00494 }
00495
00496 cvm::atom_pos cvm::atom_group::center_of_geometry (cvm::atom_pos const &ref_pos)
00497 {
00498 if (b_dummy) {
00499 cvm::select_closest_image (dummy_atom_pos, ref_pos);
00500 return dummy_atom_pos;
00501 }
00502
00503 cvm::atom_pos cog (0.0, 0.0, 0.0);
00504 for (cvm::atom_iter ai = this->begin();
00505 ai != this->end(); ai++) {
00506 cvm::select_closest_image (ai->pos, ref_pos);
00507 cog += ai->pos;
00508 }
00509 cog /= this->size();
00510 return cog;
00511 }
00512
00513 cvm::atom_pos cvm::atom_group::center_of_geometry() const
00514 {
00515 if (b_dummy)
00516 return dummy_atom_pos;
00517
00518 cvm::atom_pos cog (0.0, 0.0, 0.0);
00519 for (cvm::atom_const_iter ai = this->begin();
00520 ai != this->end(); ai++) {
00521 cog += ai->pos;
00522 }
00523 cog /= this->size();
00524 return cog;
00525 }
00526
00527 cvm::atom_pos cvm::atom_group::center_of_mass (cvm::atom_pos const &ref_pos)
00528 {
00529 if (b_dummy) {
00530 cvm::select_closest_image (dummy_atom_pos, ref_pos);
00531 return dummy_atom_pos;
00532 }
00533
00534 cvm::atom_pos com (0.0, 0.0, 0.0);
00535 for (cvm::atom_iter ai = this->begin();
00536 ai != this->end(); ai++) {
00537 cvm::select_closest_image (ai->pos, ref_pos);
00538 com += ai->mass * ai->pos;
00539 }
00540 com /= this->total_mass;
00541 return com;
00542 }
00543
00544 cvm::atom_pos cvm::atom_group::center_of_mass() const
00545 {
00546 if (b_dummy)
00547 return dummy_atom_pos;
00548
00549 cvm::atom_pos com (0.0, 0.0, 0.0);
00550 for (cvm::atom_const_iter ai = this->begin();
00551 ai != this->end(); ai++) {
00552 com += ai->mass * ai->pos;
00553 }
00554 com /= this->total_mass;
00555 return com;
00556 }
00557
00558
00559 void cvm::atom_group::set_weighted_gradient (cvm::rvector const &grad)
00560 {
00561 if (b_dummy) return;
00562
00563 for (cvm::atom_iter ai = this->begin();
00564 ai != this->end(); ai++) {
00565 ai->grad = (ai->mass/this->total_mass) * grad;
00566 }
00567 }
00568
00569
00570 std::vector<cvm::atom_pos> cvm::atom_group::positions() const
00571 {
00572 if (b_dummy)
00573 cvm::fatal_error ("Error: positions are not available "
00574 "from a dummy atom group.\n");
00575
00576 std::vector<cvm::atom_pos> x (this->size(), 0.0);
00577 cvm::atom_const_iter ai = this->begin();
00578 std::vector<cvm::atom_pos>::iterator xi = x.begin();
00579 for ( ; ai != this->end(); xi++, ai++) {
00580 *xi = ai->pos;
00581 }
00582 return x;
00583 }
00584
00585 std::vector<cvm::atom_pos> cvm::atom_group::positions_shifted (cvm::rvector const &shift) const
00586 {
00587 if (b_dummy)
00588 cvm::fatal_error ("Error: positions are not available "
00589 "from a dummy atom group.\n");
00590
00591 std::vector<cvm::atom_pos> x (this->size(), 0.0);
00592 cvm::atom_const_iter ai = this->begin();
00593 std::vector<cvm::atom_pos>::iterator xi = x.begin();
00594 for ( ; ai != this->end(); xi++, ai++) {
00595 *xi = (ai->pos + shift);
00596 }
00597 return x;
00598 }
00599
00600 std::vector<cvm::rvector> cvm::atom_group::velocities() const
00601 {
00602 if (b_dummy)
00603 cvm::fatal_error ("Error: velocities are not available "
00604 "from a dummy atom group.\n");
00605
00606 std::vector<cvm::rvector> v (this->size(), 0.0);
00607 cvm::atom_const_iter ai = this->begin();
00608 std::vector<cvm::atom_pos>::iterator vi = v.begin();
00609 for ( ; ai != this->end(); vi++, ai++) {
00610 *vi = ai->vel;
00611 }
00612 return v;
00613 }
00614
00615 std::vector<cvm::rvector> cvm::atom_group::system_forces() const
00616 {
00617 if (b_dummy)
00618 cvm::fatal_error ("Error: system forces are not available "
00619 "from a dummy atom group.\n");
00620
00621 std::vector<cvm::rvector> f (this->size(), 0.0);
00622 cvm::atom_const_iter ai = this->begin();
00623 std::vector<cvm::atom_pos>::iterator fi = f.begin();
00624 for ( ; ai != this->end(); fi++, ai++) {
00625 *fi = ai->system_force;
00626 }
00627 return f;
00628 }
00629
00630 cvm::rvector cvm::atom_group::system_force() const
00631 {
00632 if (b_dummy)
00633 cvm::fatal_error ("Error: system forces are not available "
00634 "from a dummy atom group.\n");
00635
00636 cvm::rvector f (0.0);
00637 for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) {
00638 f += ai->system_force;
00639 }
00640 return f;
00641 }
00642
00643
00644 void cvm::atom_group::apply_colvar_force (cvm::real const &force)
00645 {
00646 if (b_dummy)
00647 return;
00648
00649 if (noforce)
00650 cvm::fatal_error ("Error: sending a force to a group that has "
00651 "\"disableForces\" defined.\n");
00652
00653 if (b_rotate) {
00654
00655
00656 cvm::rotation const rot_inv = rot.inverse();
00657 for (cvm::atom_iter ai = this->begin();
00658 ai != this->end(); ai++) {
00659 ai->apply_force (rot_inv.rotate (force * ai->grad));
00660 }
00661
00662 } else {
00663
00664
00665
00666 for (cvm::atom_iter ai = this->begin();
00667 ai != this->end(); ai++) {
00668 ai->apply_force (force * ai->grad);
00669 }
00670 }
00671 }
00672
00673
00674 void cvm::atom_group::apply_force (cvm::rvector const &force)
00675 {
00676 if (b_dummy)
00677 return;
00678
00679 if (noforce)
00680 cvm::fatal_error ("Error: sending a force to a group that has "
00681 "\"disableForces\" defined.\n");
00682
00683 if (b_rotate) {
00684
00685 cvm::rotation const rot_inv = rot.inverse();
00686 for (cvm::atom_iter ai = this->begin();
00687 ai != this->end(); ai++) {
00688 ai->apply_force (rot_inv.rotate ((ai->mass/this->total_mass) * force));
00689 }
00690
00691 } else {
00692
00693 for (cvm::atom_iter ai = this->begin();
00694 ai != this->end(); ai++) {
00695 ai->apply_force ((ai->mass/this->total_mass) * force);
00696 }
00697 }
00698 }
00699
00700
00701 void cvm::atom_group::apply_forces (std::vector<cvm::rvector> const &forces)
00702 {
00703 if (b_dummy)
00704 return;
00705
00706 if (noforce)
00707 cvm::fatal_error ("Error: sending a force to a group that has "
00708 "\"disableForces\" defined.\n");
00709
00710 if (forces.size() != this->size()) {
00711 cvm::fatal_error ("Error: trying to apply an array of forces to an atom "
00712 "group which does not have the same length.\n");
00713 }
00714
00715 if (b_rotate) {
00716
00717 cvm::rotation const rot_inv = rot.inverse();
00718 cvm::atom_iter ai = this->begin();
00719 std::vector<cvm::rvector>::const_iterator fi = forces.begin();
00720 for ( ; ai != this->end(); fi++, ai++) {
00721 ai->apply_force (rot_inv.rotate (*fi));
00722 }
00723
00724 } else {
00725
00726 cvm::atom_iter ai = this->begin();
00727 std::vector<cvm::rvector>::const_iterator fi = forces.begin();
00728 for ( ; ai != this->end(); fi++, ai++) {
00729 ai->apply_force (*fi);
00730 }
00731 }
00732 }
00733
00734