00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <algorithm>
00011
00012 #include "colvarmodule.h"
00013 #include "colvarvalue.h"
00014 #include "colvar.h"
00015 #include "colvarcomp.h"
00016
00017
00018
00019 colvar::cvc::cvc()
00020 {
00021 description = "uninitialized colvar component";
00022 b_try_scalable = true;
00023 sup_coeff = 1.0;
00024 sup_np = 1;
00025 period = 0.0;
00026 wrap_center = 0.0;
00027 width = 0.0;
00028 cvc::init_dependencies();
00029 }
00030
00031
00032 colvar::cvc::cvc(std::string const &conf)
00033 {
00034 description = "uninitialized colvar component";
00035 b_try_scalable = true;
00036 sup_coeff = 1.0;
00037 sup_np = 1;
00038 period = 0.0;
00039 wrap_center = 0.0;
00040 width = 0.0;
00041 init_dependencies();
00042 colvar::cvc::init(conf);
00043 }
00044
00045
00046 int colvar::cvc::set_function_type(std::string const &type)
00047 {
00048 function_type = type;
00049 if (function_types.size() == 0) {
00050 function_types.push_back(function_type);
00051 } else {
00052 if (function_types.back() != function_type) {
00053 function_types.push_back(function_type);
00054 }
00055 }
00056 for (size_t i = function_types.size()-1; i > 0; i--) {
00057 cvm::main()->cite_feature(function_types[i]+" colvar component"+
00058 " (derived from "+function_types[i-1]+")");
00059 }
00060 cvm::main()->cite_feature(function_types[0]+" colvar component");
00061 return COLVARS_OK;
00062 }
00063
00064
00065 int colvar::cvc::init(std::string const &conf)
00066 {
00067 if (cvm::debug())
00068 cvm::log("Initializing cvc base object.\n");
00069
00070 std::string const old_name(name);
00071
00072 if (name.size() > 0) {
00073 cvm::log("Updating configuration for component \""+name+"\"\n");
00074 }
00075
00076 if (get_keyval(conf, "name", name, name)) {
00077 if (name.size() > 0) {
00078 description = "cvc \"" + name + "\" of type " + function_type;
00079 } else {
00080 description = "unnamed cvc";
00081 }
00082 if ((name != old_name) && (old_name.size() > 0)) {
00083 cvm::error("Error: cannot rename component \""+old_name+
00084 "\" after initialization (new name = \""+name+"\")",
00085 COLVARS_INPUT_ERROR);
00086 name = old_name;
00087 }
00088 }
00089
00090 get_keyval(conf, "componentCoeff", sup_coeff, sup_coeff);
00091 get_keyval(conf, "componentExp", sup_np, sup_np);
00092 if (sup_coeff != 1.0 || sup_np != 1) {
00093 cvm::main()->cite_feature("Linear and polynomial combination of colvar components");
00094 }
00095
00096 register_param("componentCoeff", reinterpret_cast<void *>(&sup_coeff));
00097 register_param("componentExp", reinterpret_cast<void *>(&sup_np));
00098
00099 get_keyval(conf, "period", period, period);
00100 get_keyval(conf, "wrapAround", wrap_center, wrap_center);
00101
00102 register_param("period", reinterpret_cast<void *>(&period));
00103 register_param("wrapAround", reinterpret_cast<void *>(&wrap_center));
00104
00105 get_keyval_feature(this, conf, "debugGradients",
00106 f_cvc_debug_gradient, false, parse_silent);
00107
00108 bool b_no_PBC = !is_enabled(f_cvc_pbc_minimum_image);
00109 get_keyval(conf, "forceNoPBC", b_no_PBC, b_no_PBC);
00110 if (b_no_PBC) {
00111 disable(f_cvc_pbc_minimum_image);
00112 } else {
00113 enable(f_cvc_pbc_minimum_image);
00114 }
00115
00116
00117 get_keyval(conf, "scalable", b_try_scalable, b_try_scalable);
00118
00119 if (cvm::debug())
00120 cvm::log("Done initializing cvc base object.\n");
00121
00122 return cvm::get_error();
00123 }
00124
00125
00126 int colvar::cvc::init_total_force_params(std::string const &conf)
00127 {
00128 if (cvm::get_error()) return COLVARS_ERROR;
00129
00130 if (get_keyval_feature(this, conf, "oneSiteSystemForce",
00131 f_cvc_one_site_total_force, is_enabled(f_cvc_one_site_total_force))) {
00132 cvm::log("Warning: keyword \"oneSiteSystemForce\" is deprecated: "
00133 "please use \"oneSiteTotalForce\" instead.\n");
00134 }
00135 if (get_keyval_feature(this, conf, "oneSiteTotalForce",
00136 f_cvc_one_site_total_force, is_enabled(f_cvc_one_site_total_force))) {
00137 cvm::log("Computing total force on group 1 only\n");
00138 }
00139
00140 if (! is_enabled(f_cvc_one_site_total_force)) {
00141
00142 std::vector<cvm::atom_group *>::iterator agi = atom_groups.begin();
00143 agi++;
00144 for ( ; agi != atom_groups.end(); agi++) {
00145 if ((*agi)->b_dummy) {
00146 provide(f_cvc_inv_gradient, false);
00147 provide(f_cvc_Jacobian, false);
00148 }
00149 }
00150 }
00151
00152 return COLVARS_OK;
00153 }
00154
00155
00156 cvm::atom_group *colvar::cvc::parse_group(std::string const &conf,
00157 char const *group_key,
00158 bool optional)
00159 {
00160 cvm::atom_group *group = NULL;
00161 std::string group_conf;
00162
00163 if (key_lookup(conf, group_key, &group_conf)) {
00164 group = new cvm::atom_group(group_key);
00165
00166 if (b_try_scalable) {
00167 if (is_available(f_cvc_scalable_com)
00168 && is_enabled(f_cvc_com_based)
00169 && !is_enabled(f_cvc_debug_gradient)) {
00170 disable(f_cvc_explicit_gradient);
00171 enable(f_cvc_scalable_com);
00172
00173
00174 group->provide(f_ag_scalable_com);
00175 }
00176
00177
00178 }
00179
00180 if (group_conf.size() == 0) {
00181 cvm::error("Error: atom group \""+group->key+
00182 "\" is set, but has no definition.\n",
00183 COLVARS_INPUT_ERROR);
00184 return group;
00185 }
00186
00187 cvm::increase_depth();
00188 if (group->parse(group_conf) == COLVARS_OK) {
00189 register_atom_group(group);
00190 }
00191 group->check_keywords(group_conf, group_key);
00192 if (cvm::get_error()) {
00193 cvm::error("Error parsing definition for atom group \""+
00194 std::string(group_key)+"\".", COLVARS_INPUT_ERROR);
00195 }
00196 cvm::decrease_depth();
00197
00198 } else {
00199 if (! optional) {
00200 cvm::error("Error: definition for atom group \""+
00201 std::string(group_key)+"\" not found.\n");
00202 }
00203 }
00204
00205 return group;
00206 }
00207
00208
00209 int colvar::cvc::init_dependencies() {
00210 size_t i;
00211
00212 if (features().size() == 0) {
00213 for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
00214 modify_features().push_back(new feature);
00215 }
00216
00217 init_feature(f_cvc_active, "active", f_type_dynamic);
00218
00219
00220
00221 init_feature(f_cvc_scalar, "scalar", f_type_static);
00222
00223 init_feature(f_cvc_periodic, "periodic", f_type_static);
00224
00225 init_feature(f_cvc_width, "defined_width", f_type_static);
00226
00227 init_feature(f_cvc_lower_boundary, "defined_lower_boundary", f_type_static);
00228
00229 init_feature(f_cvc_upper_boundary, "defined_upper_boundary", f_type_static);
00230
00231 init_feature(f_cvc_gradient, "gradient", f_type_dynamic);
00232
00233 init_feature(f_cvc_explicit_gradient, "explicit_gradient", f_type_static);
00234 require_feature_children(f_cvc_explicit_gradient, f_ag_explicit_gradient);
00235
00236 init_feature(f_cvc_inv_gradient, "inverse_gradient", f_type_dynamic);
00237 require_feature_self(f_cvc_inv_gradient, f_cvc_gradient);
00238
00239 init_feature(f_cvc_debug_gradient, "debug_gradient", f_type_user);
00240 require_feature_self(f_cvc_debug_gradient, f_cvc_gradient);
00241 require_feature_self(f_cvc_debug_gradient, f_cvc_explicit_gradient);
00242
00243 init_feature(f_cvc_Jacobian, "Jacobian_derivative", f_type_dynamic);
00244 require_feature_self(f_cvc_Jacobian, f_cvc_inv_gradient);
00245
00246
00247
00248 init_feature(f_cvc_one_site_total_force, "total_force_from_one_group", f_type_user);
00249 require_feature_self(f_cvc_one_site_total_force, f_cvc_com_based);
00250
00251 init_feature(f_cvc_com_based, "function_of_centers_of_mass", f_type_static);
00252
00253 init_feature(f_cvc_pbc_minimum_image, "use_minimum-image_with_PBCs", f_type_user);
00254
00255 init_feature(f_cvc_scalable, "scalable_calculation", f_type_dynamic);
00256 require_feature_self(f_cvc_scalable_com, f_cvc_scalable);
00257
00258 exclude_feature_self(f_cvc_scalable, f_cvc_explicit_gradient);
00259
00260 init_feature(f_cvc_scalable_com, "scalable_calculation_of_centers_of_mass", f_type_static);
00261 require_feature_self(f_cvc_scalable_com, f_cvc_com_based);
00262
00263 exclude_feature_self(f_cvc_scalable_com, f_cvc_explicit_gradient);
00264
00265 init_feature(f_cvc_collect_atom_ids, "collect_atom_ids", f_type_dynamic);
00266 require_feature_children(f_cvc_collect_atom_ids, f_ag_collect_atom_ids);
00267
00268
00269
00270
00271
00272
00273 for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
00274 if (is_not_set(i)) {
00275 cvm::error("Uninitialized feature " + cvm::to_str(i) + " in " + description);
00276 }
00277 }
00278 }
00279
00280
00281
00282
00283 feature_states.reserve(f_cvc_ntot);
00284 for (i = 0; i < colvardeps::f_cvc_ntot; i++) {
00285 bool avail = is_dynamic(i) ? false : true;
00286 feature_states.push_back(feature_state(avail, false));
00287 }
00288
00289
00290
00291 feature_states[f_cvc_active].available = true;
00292 feature_states[f_cvc_gradient].available = true;
00293 feature_states[f_cvc_collect_atom_ids].available = true;
00294
00295
00296 enable(f_cvc_active);
00297
00298
00299 enable(f_cvc_explicit_gradient);
00300
00301
00302 enable(f_cvc_pbc_minimum_image);
00303
00304
00305 feature_states[f_cvc_one_site_total_force].available = true;
00306
00307
00308 feature_states[f_cvc_scalable_com].available = (cvm::proxy->scalable_group_coms() == COLVARS_OK);
00309 feature_states[f_cvc_scalable].available = feature_states[f_cvc_scalable_com].available;
00310
00311 return COLVARS_OK;
00312 }
00313
00314
00315 int colvar::cvc::setup()
00316 {
00317 description = "cvc " + name;
00318 return COLVARS_OK;
00319 }
00320
00321
00322 colvar::cvc::~cvc()
00323 {
00324 free_children_deps();
00325 remove_all_children();
00326 for (size_t i = 0; i < atom_groups.size(); i++) {
00327 if (atom_groups[i] != NULL) delete atom_groups[i];
00328 }
00329 }
00330
00331
00332 void colvar::cvc::init_as_distance()
00333 {
00334 x.type(colvarvalue::type_scalar);
00335 enable(f_cvc_lower_boundary);
00336 lower_boundary.type(colvarvalue::type_scalar);
00337 lower_boundary.real_value = 0.0;
00338 register_param("lowerBoundary", reinterpret_cast<void *>(&lower_boundary));
00339 }
00340
00341
00342 void colvar::cvc::init_as_angle()
00343 {
00344 x.type(colvarvalue::type_scalar);
00345 init_scalar_boundaries(0.0, 180.0);
00346 }
00347
00348
00349 void colvar::cvc::init_as_periodic_angle()
00350 {
00351 x.type(colvarvalue::type_scalar);
00352 enable(f_cvc_periodic);
00353 period = 360.0;
00354 init_scalar_boundaries(-180.0, 180.0);
00355 }
00356
00357
00358 void colvar::cvc::init_scalar_boundaries(cvm::real lb, cvm::real ub)
00359 {
00360 enable(f_cvc_lower_boundary);
00361 lower_boundary.type(colvarvalue::type_scalar);
00362 lower_boundary.real_value = lb;
00363 enable(f_cvc_upper_boundary);
00364 upper_boundary.type(colvarvalue::type_scalar);
00365 upper_boundary.real_value = ub;
00366 register_param("lowerBoundary", reinterpret_cast<void *>(&lower_boundary));
00367 register_param("upperBoundary", reinterpret_cast<void *>(&upper_boundary));
00368 }
00369
00370
00371 void colvar::cvc::register_atom_group(cvm::atom_group *ag)
00372 {
00373 atom_groups.push_back(ag);
00374 add_child(ag);
00375 }
00376
00377
00378 colvarvalue const *colvar::cvc::get_param_grad(std::string const ¶m_name)
00379 {
00380 colvarvalue const *ptr =
00381 reinterpret_cast<colvarvalue const *>(get_param_grad_ptr(param_name));
00382 return ptr != NULL ? ptr : NULL;
00383 }
00384
00385
00386 int colvar::cvc::set_param(std::string const ¶m_name,
00387 void const *new_value)
00388 {
00389 if (param_map.count(param_name) > 0) {
00390
00391
00392 if (param_name.compare("componentCoeff") == 0) {
00393 sup_coeff = *(reinterpret_cast<cvm::real const *>(new_value));
00394 }
00395 if (param_name.compare("componentExp") == 0) {
00396 sup_np = *(reinterpret_cast<int const *>(new_value));
00397 }
00398 if (is_enabled(f_cvc_periodic)) {
00399 if (param_name.compare("period") == 0) {
00400 period = *(reinterpret_cast<cvm::real const *>(new_value));
00401 }
00402 if (param_name.compare("wrapAround") == 0) {
00403 wrap_center = *(reinterpret_cast<cvm::real const *>(new_value));
00404 }
00405 }
00406 }
00407
00408 return colvarparams::set_param(param_name, new_value);
00409 }
00410
00411
00412 void colvar::cvc::read_data()
00413 {
00414 size_t ig;
00415 for (ig = 0; ig < atom_groups.size(); ig++) {
00416 cvm::atom_group &atoms = *(atom_groups[ig]);
00417 atoms.reset_atoms_data();
00418 atoms.read_positions();
00419 atoms.calc_required_properties();
00420
00421 }
00422
00424
00425
00426
00427
00428
00429
00430
00431 }
00432
00433
00434 std::vector<std::vector<int> > colvar::cvc::get_atom_lists()
00435 {
00436 std::vector<std::vector<int> > lists;
00437
00438 std::vector<cvm::atom_group *>::iterator agi = atom_groups.begin();
00439 for ( ; agi != atom_groups.end(); ++agi) {
00440 (*agi)->create_sorted_ids();
00441 lists.push_back((*agi)->sorted_ids());
00442 if ((*agi)->is_enabled(f_ag_fitting_group) && (*agi)->is_enabled(f_ag_fit_gradients)) {
00443 cvm::atom_group &fg = *((*agi)->fitting_group);
00444 fg.create_sorted_ids();
00445 lists.push_back(fg.sorted_ids());
00446 }
00447 }
00448 return lists;
00449 }
00450
00451
00452 void colvar::cvc::collect_gradients(std::vector<int> const &atom_ids, std::vector<cvm::rvector> &atomic_gradients)
00453 {
00454
00455 cvm::real coeff = sup_coeff * cvm::real(sup_np) *
00456 cvm::integer_power(value().real_value, sup_np-1);
00457
00458 for (size_t j = 0; j < atom_groups.size(); j++) {
00459
00460 cvm::atom_group &ag = *(atom_groups[j]);
00461
00462
00463
00464 if (ag.is_enabled(f_ag_rotate)) {
00465 cvm::rotation const rot_inv = ag.rot.inverse();
00466
00467 for (size_t k = 0; k < ag.size(); k++) {
00468 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
00469 ag[k].id) - atom_ids.begin();
00470 atomic_gradients[a] += coeff * rot_inv.rotate(ag[k].grad);
00471 }
00472
00473 } else {
00474
00475 for (size_t k = 0; k < ag.size(); k++) {
00476 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
00477 ag[k].id) - atom_ids.begin();
00478 atomic_gradients[a] += coeff * ag[k].grad;
00479 }
00480 }
00481 if (ag.is_enabled(f_ag_fitting_group) && ag.is_enabled(f_ag_fit_gradients)) {
00482 cvm::atom_group const &fg = *(ag.fitting_group);
00483 for (size_t k = 0; k < fg.size(); k++) {
00484 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
00485 fg[k].id) - atom_ids.begin();
00486
00487 atomic_gradients[a] += coeff * fg.fit_gradients[k];
00488 }
00489 }
00490 }
00491 }
00492
00493
00494 void colvar::cvc::calc_force_invgrads()
00495 {
00496 cvm::error("Error: calculation of inverse gradients is not implemented "
00497 "for colvar components of type \""+function_type+"\".\n",
00498 COLVARS_NOT_IMPLEMENTED);
00499 }
00500
00501
00502 void colvar::cvc::calc_Jacobian_derivative()
00503 {
00504 cvm::error("Error: calculation of inverse gradients is not implemented "
00505 "for colvar components of type \""+function_type+"\".\n",
00506 COLVARS_NOT_IMPLEMENTED);
00507 }
00508
00509
00510 void colvar::cvc::calc_fit_gradients()
00511 {
00512 for (size_t ig = 0; ig < atom_groups.size(); ig++) {
00513 atom_groups[ig]->calc_fit_gradients();
00514 }
00515 }
00516
00517
00518 void colvar::cvc::debug_gradients()
00519 {
00520
00521
00522
00523
00524
00525 cvm::log("Debugging gradients for " + description);
00526
00527 for (size_t ig = 0; ig < atom_groups.size(); ig++) {
00528 cvm::atom_group *group = atom_groups[ig];
00529 if (group->b_dummy) continue;
00530
00531 cvm::rotation const rot_0 = group->rot;
00532 cvm::rotation const rot_inv = group->rot.inverse();
00533
00534 cvm::real x_0 = x.real_value;
00535 if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0];
00536
00537
00538
00539 cvm::atom_group *group_for_fit = group->fitting_group ? group->fitting_group : group;
00540 cvm::atom_pos fit_gradient_sum, gradient_sum;
00541
00542
00543 if (group->is_enabled(f_ag_center) || group->is_enabled(f_ag_rotate)) {
00544 if (group->is_enabled(f_ag_fit_gradients)) {
00545 size_t j;
00546
00547
00548 cvm::log("Fit gradients:\n");
00549 for (j = 0; j < group_for_fit->fit_gradients.size(); j++) {
00550 cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) +
00551 "[" + cvm::to_str(j) + "] = " +
00552 (group->is_enabled(f_ag_rotate) ?
00553 cvm::to_str(rot_0.rotate(group_for_fit->fit_gradients[j])) :
00554 cvm::to_str(group_for_fit->fit_gradients[j])));
00555 }
00556 }
00557 }
00558
00559
00560 for (size_t ia = 0; ia < group->size(); ia++) {
00561
00562
00563 cvm::rvector const atom_grad = (group->is_enabled(f_ag_rotate) ?
00564 rot_inv.rotate((*group)[ia].grad) :
00565 (*group)[ia].grad);
00566 gradient_sum += atom_grad;
00567
00568 for (size_t id = 0; id < 3; id++) {
00569
00570 group->read_positions();
00571
00572 (*group)[ia].pos[id] += cvm::debug_gradients_step_size;
00573 group->calc_required_properties();
00574 calc_value();
00575 cvm::real x_1 = x.real_value;
00576 if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_1 = x[0];
00577 cvm::log("Atom "+cvm::to_str(ia)+", component "+cvm::to_str(id)+":\n");
00578 cvm::log("dx(actual) = "+cvm::to_str(x_1 - x_0,
00579 21, 14)+"\n");
00580 cvm::real const dx_pred = (group->fit_gradients.size()) ?
00581 (cvm::debug_gradients_step_size * (atom_grad[id] + group->fit_gradients[ia][id])) :
00582 (cvm::debug_gradients_step_size * atom_grad[id]);
00583 cvm::log("dx(interp) = "+cvm::to_str(dx_pred,
00584 21, 14)+"\n");
00585 cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+
00586 cvm::to_str(cvm::fabs(x_1 - x_0 - dx_pred) /
00587 cvm::fabs(x_1 - x_0), 12, 5)+"\n");
00588 }
00589 }
00590
00591 if ((group->is_enabled(f_ag_fit_gradients)) && (group->fitting_group != NULL)) {
00592 cvm::atom_group *ref_group = group->fitting_group;
00593 group->read_positions();
00594 group->calc_required_properties();
00595
00596 for (size_t ia = 0; ia < ref_group->size(); ia++) {
00597
00598
00599 cvm::rvector const atom_grad = ref_group->fit_gradients[ia];
00600 fit_gradient_sum += atom_grad;
00601
00602 for (size_t id = 0; id < 3; id++) {
00603
00604 group->read_positions();
00605 ref_group->read_positions();
00606
00607 (*ref_group)[ia].pos[id] += cvm::debug_gradients_step_size;
00608 group->calc_required_properties();
00609 calc_value();
00610
00611 cvm::real const x_1 = x.real_value;
00612 cvm::log("refPosGroup atom "+cvm::to_str(ia)+", component "+cvm::to_str (id)+":\n");
00613 cvm::log("dx(actual) = "+cvm::to_str (x_1 - x_0,
00614 21, 14)+"\n");
00615
00616 cvm::real const dx_pred = cvm::debug_gradients_step_size * atom_grad[id];
00617
00618 cvm::log("dx(interp) = "+cvm::to_str (dx_pred,
00619 21, 14)+"\n");
00620 cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+
00621 cvm::to_str(cvm::fabs (x_1 - x_0 - dx_pred) /
00622 cvm::fabs (x_1 - x_0),
00623 12, 5)+
00624 ".\n");
00625 }
00626 }
00627 }
00628
00629 cvm::log("Gradient sum: " + cvm::to_str(gradient_sum) +
00630 " Fit gradient sum: " + cvm::to_str(fit_gradient_sum) +
00631 " Total " + cvm::to_str(gradient_sum + fit_gradient_sum));
00632 }
00633 return;
00634 }
00635
00636
00637 cvm::real colvar::cvc::dist2(colvarvalue const &x1,
00638 colvarvalue const &x2) const
00639 {
00640 return x1.dist2(x2);
00641 }
00642
00643
00644 colvarvalue colvar::cvc::dist2_lgrad(colvarvalue const &x1,
00645 colvarvalue const &x2) const
00646 {
00647 return x1.dist2_grad(x2);
00648 }
00649
00650
00651 colvarvalue colvar::cvc::dist2_rgrad(colvarvalue const &x1,
00652 colvarvalue const &x2) const
00653 {
00654 return x2.dist2_grad(x1);
00655 }
00656
00657
00658 void colvar::cvc::wrap(colvarvalue & ) const
00659 {
00660 return;
00661 }
00662
00663
00664
00665
00666
00667 std::vector<colvardeps::feature *> colvar::cvc::cvc_features;