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 colvar::alpha_angles::alpha_angles(std::string const &conf)
00020 : cvc(conf)
00021 {
00022 set_function_type("alpha");
00023 enable(f_cvc_explicit_gradient);
00024 x.type(colvarvalue::type_scalar);
00025
00026 colvarproxy *proxy = cvm::main()->proxy;
00027
00028 std::string segment_id;
00029 get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
00030
00031 std::vector<int> residues;
00032 {
00033 std::string residues_conf = "";
00034 key_lookup(conf, "residueRange", &residues_conf);
00035 if (residues_conf.size()) {
00036 std::istringstream is(residues_conf);
00037 int initial, final;
00038 char dash;
00039 if ( (is >> initial) && (initial > 0) &&
00040 (is >> dash) && (dash == '-') &&
00041 (is >> final) && (final > 0) ) {
00042 for (int rnum = initial; rnum <= final; rnum++) {
00043 residues.push_back(rnum);
00044 }
00045 }
00046 } else {
00047 cvm::error("Error: no residues defined in \"residueRange\".\n");
00048 return;
00049 }
00050 }
00051
00052 if (residues.size() < 5) {
00053 cvm::error("Error: not enough residues defined in \"residueRange\".\n");
00054 return;
00055 }
00056
00057 std::string const &sid = segment_id;
00058 std::vector<int> const &r = residues;
00059
00060
00061 get_keyval(conf, "hBondCoeff", hb_coeff, 0.5);
00062 if ( (hb_coeff < 0.0) || (hb_coeff > 1.0) ) {
00063 cvm::error("Error: hBondCoeff must be defined between 0 and 1.\n");
00064 return;
00065 }
00066
00067
00068 get_keyval(conf, "angleRef", theta_ref, 88.0);
00069 get_keyval(conf, "angleTol", theta_tol, 15.0);
00070
00071 if (hb_coeff < 1.0) {
00072
00073 for (size_t i = 0; i < residues.size()-2; i++) {
00074 theta.push_back(new colvar::angle(cvm::atom(r[i ], "CA", sid),
00075 cvm::atom(r[i+1], "CA", sid),
00076 cvm::atom(r[i+2], "CA", sid)));
00077 register_atom_group(theta.back()->atom_groups[0]);
00078 register_atom_group(theta.back()->atom_groups[1]);
00079 register_atom_group(theta.back()->atom_groups[2]);
00080 }
00081
00082 } else {
00083 cvm::log("The hBondCoeff specified will disable the Calpha-Calpha-Calpha angle terms.\n");
00084 }
00085
00086 {
00087 cvm::real r0;
00088 size_t en, ed;
00089 get_keyval(conf, "hBondCutoff", r0, proxy->angstrom_to_internal(3.3));
00090 get_keyval(conf, "hBondExpNumer", en, 6);
00091 get_keyval(conf, "hBondExpDenom", ed, 8);
00092
00093 if (hb_coeff > 0.0) {
00094
00095 for (size_t i = 0; i < residues.size()-4; i++) {
00096 hb.push_back(new colvar::h_bond(cvm::atom(r[i ], "O", sid),
00097 cvm::atom(r[i+4], "N", sid),
00098 r0, en, ed));
00099 register_atom_group(hb.back()->atom_groups[0]);
00100 }
00101
00102 } else {
00103 cvm::log("The hBondCoeff specified will disable the hydrogen bond terms.\n");
00104 }
00105 }
00106 }
00107
00108
00109 colvar::alpha_angles::alpha_angles()
00110 : cvc()
00111 {
00112 set_function_type("alphaAngles");
00113 enable(f_cvc_explicit_gradient);
00114 x.type(colvarvalue::type_scalar);
00115 }
00116
00117
00118 colvar::alpha_angles::~alpha_angles()
00119 {
00120 while (theta.size() != 0) {
00121 delete theta.back();
00122 theta.pop_back();
00123 }
00124 while (hb.size() != 0) {
00125 delete hb.back();
00126 hb.pop_back();
00127 }
00128
00129 atom_groups.clear();
00130 }
00131
00132
00133 void colvar::alpha_angles::calc_value()
00134 {
00135 x.real_value = 0.0;
00136
00137 if (theta.size()) {
00138
00139 cvm::real const theta_norm =
00140 (1.0-hb_coeff) / cvm::real(theta.size());
00141
00142 for (size_t i = 0; i < theta.size(); i++) {
00143
00144 (theta[i])->calc_value();
00145
00146 cvm::real const t = ((theta[i])->value().real_value-theta_ref)/theta_tol;
00147 cvm::real const f = ( (1.0 - (t*t)) /
00148 (1.0 - (t*t*t*t)) );
00149
00150 x.real_value += theta_norm * f;
00151
00152 if (cvm::debug())
00153 cvm::log("Calpha-Calpha angle no. "+cvm::to_str(i+1)+" in \""+
00154 this->name+"\" has a value of "+
00155 (cvm::to_str((theta[i])->value().real_value))+
00156 " degrees, f = "+cvm::to_str(f)+".\n");
00157 }
00158 }
00159
00160 if (hb.size()) {
00161
00162 cvm::real const hb_norm =
00163 hb_coeff / cvm::real(hb.size());
00164
00165 for (size_t i = 0; i < hb.size(); i++) {
00166 (hb[i])->calc_value();
00167 x.real_value += hb_norm * (hb[i])->value().real_value;
00168 if (cvm::debug())
00169 cvm::log("Hydrogen bond no. "+cvm::to_str(i+1)+" in \""+
00170 this->name+"\" has a value of "+
00171 (cvm::to_str((hb[i])->value().real_value))+".\n");
00172 }
00173 }
00174 }
00175
00176
00177 void colvar::alpha_angles::calc_gradients()
00178 {
00179 size_t i;
00180 for (i = 0; i < theta.size(); i++)
00181 (theta[i])->calc_gradients();
00182
00183 for (i = 0; i < hb.size(); i++)
00184 (hb[i])->calc_gradients();
00185 }
00186
00187
00188 void colvar::alpha_angles::collect_gradients(std::vector<int> const &atom_ids, std::vector<cvm::rvector> &atomic_gradients)
00189 {
00190 cvm::real cvc_coeff = sup_coeff * cvm::real(sup_np) * cvm::integer_power(value().real_value, sup_np-1);
00191
00192 if (theta.size()) {
00193 cvm::real const theta_norm = (1.0-hb_coeff) / cvm::real(theta.size());
00194
00195 for (size_t i = 0; i < theta.size(); i++) {
00196 cvm::real const t = ((theta[i])->value().real_value-theta_ref)/theta_tol;
00197 cvm::real const f = ( (1.0 - (t*t)) /
00198 (1.0 - (t*t*t*t)) );
00199 cvm::real const dfdt =
00200 1.0/(1.0 - (t*t*t*t)) *
00201 ( (-2.0 * t) + (-1.0*f)*(-4.0 * (t*t*t)) );
00202
00203
00204
00205 cvm::real const coeff = cvc_coeff * theta_norm * dfdt * (1.0/theta_tol);
00206
00207 for (size_t j = 0; j < theta[i]->atom_groups.size(); j++) {
00208 cvm::atom_group &ag = *(theta[i]->atom_groups[j]);
00209 for (size_t k = 0; k < ag.size(); k++) {
00210 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
00211 ag[k].id) - atom_ids.begin();
00212 atomic_gradients[a] += coeff * ag[k].grad;
00213 }
00214 }
00215 }
00216 }
00217
00218 if (hb.size()) {
00219
00220 cvm::real const hb_norm = hb_coeff / cvm::real(hb.size());
00221
00222 for (size_t i = 0; i < hb.size(); i++) {
00223
00224
00225 cvm::real const coeff = cvc_coeff * 0.5 * hb_norm;
00226
00227 for (size_t j = 0; j < hb[i]->atom_groups.size(); j++) {
00228 cvm::atom_group &ag = *(hb[i]->atom_groups[j]);
00229 for (size_t k = 0; k < ag.size(); k++) {
00230 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
00231 ag[k].id) - atom_ids.begin();
00232 atomic_gradients[a] += coeff * ag[k].grad;
00233 }
00234 }
00235 }
00236 }
00237 }
00238
00239
00240 void colvar::alpha_angles::apply_force(colvarvalue const &force)
00241 {
00242
00243 if (theta.size()) {
00244
00245 cvm::real const theta_norm =
00246 (1.0-hb_coeff) / cvm::real(theta.size());
00247
00248 for (size_t i = 0; i < theta.size(); i++) {
00249
00250 cvm::real const t = ((theta[i])->value().real_value-theta_ref)/theta_tol;
00251 cvm::real const f = ( (1.0 - (t*t)) /
00252 (1.0 - (t*t*t*t)) );
00253
00254 cvm::real const dfdt =
00255 1.0/(1.0 - (t*t*t*t)) *
00256 ( (-2.0 * t) + (-1.0*f)*(-4.0 * (t*t*t)) );
00257
00258 (theta[i])->apply_force(theta_norm *
00259 dfdt * (1.0/theta_tol) *
00260 force.real_value );
00261 }
00262 }
00263
00264 if (hb.size()) {
00265
00266 cvm::real const hb_norm =
00267 hb_coeff / cvm::real(hb.size());
00268
00269 for (size_t i = 0; i < hb.size(); i++) {
00270 (hb[i])->apply_force(0.5 * hb_norm * force.real_value);
00271 }
00272 }
00273 }
00274
00275
00276 simple_scalar_dist_functions(alpha_angles)
00277
00278
00279
00281
00283
00284 colvar::dihedPC::dihedPC(std::string const &conf)
00285 : cvc(conf)
00286 {
00287 if (cvm::debug())
00288 cvm::log("Initializing dihedral PC object.\n");
00289
00290 set_function_type("dihedPC");
00291
00292 enable(f_cvc_explicit_gradient);
00293 x.type(colvarvalue::type_scalar);
00294
00295 std::string segment_id;
00296 get_keyval(conf, "psfSegID", segment_id, std::string("MAIN"));
00297
00298 std::vector<int> residues;
00299 {
00300 std::string residues_conf = "";
00301 key_lookup(conf, "residueRange", &residues_conf);
00302 if (residues_conf.size()) {
00303 std::istringstream is(residues_conf);
00304 int initial, final;
00305 char dash;
00306 if ( (is >> initial) && (initial > 0) &&
00307 (is >> dash) && (dash == '-') &&
00308 (is >> final) && (final > 0) ) {
00309 for (int rnum = initial; rnum <= final; rnum++) {
00310 residues.push_back(rnum);
00311 }
00312 }
00313 } else {
00314 cvm::error("Error: no residues defined in \"residueRange\".\n");
00315 return;
00316 }
00317 }
00318
00319 if (residues.size() < 2) {
00320 cvm::error("Error: dihedralPC requires at least two residues.\n");
00321 return;
00322 }
00323
00324 std::string const &sid = segment_id;
00325 std::vector<int> const &r = residues;
00326
00327 std::string vecFileName;
00328 int vecNumber;
00329 if (get_keyval(conf, "vectorFile", vecFileName, vecFileName)) {
00330 get_keyval(conf, "vectorNumber", vecNumber, 0);
00331 if (vecNumber < 1) {
00332 cvm::error("A positive value of vectorNumber is required.");
00333 return;
00334 }
00335
00336 std::istream &vecFile =
00337 cvm::main()->proxy->input_stream(vecFileName,
00338 "dihedral PCA vector file");
00339 if (!vecFile) {
00340 return;
00341 }
00342
00343
00344 bool eigenvectors_as_columns = true;
00345
00346 if (eigenvectors_as_columns) {
00347
00348 std::string line;
00349 cvm::real c;
00350 while (vecFile.good()) {
00351 getline(vecFile, line);
00352 if (line.length() < 2) break;
00353 std::istringstream ls(line);
00354 for (int i=0; i<vecNumber; i++) ls >> c;
00355 coeffs.push_back(c);
00356 }
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 cvm::main()->proxy->close_input_stream(vecFileName);
00380
00381 } else {
00382 get_keyval(conf, "vector", coeffs, coeffs);
00383 }
00384
00385 if ( coeffs.size() != 4 * (residues.size() - 1)) {
00386 cvm::error("Error: wrong number of coefficients: " +
00387 cvm::to_str(coeffs.size()) + ". Expected " +
00388 cvm::to_str(4 * (residues.size() - 1)) +
00389 " (4 coeffs per residue, minus one residue).\n");
00390 return;
00391 }
00392
00393 for (size_t i = 0; i < residues.size()-1; i++) {
00394
00395 theta.push_back(new colvar::dihedral(cvm::atom(r[i ], "N", sid),
00396 cvm::atom(r[i ], "CA", sid),
00397 cvm::atom(r[i ], "C", sid),
00398 cvm::atom(r[i+1], "N", sid)));
00399 register_atom_group(theta.back()->atom_groups[0]);
00400 register_atom_group(theta.back()->atom_groups[1]);
00401 register_atom_group(theta.back()->atom_groups[2]);
00402 register_atom_group(theta.back()->atom_groups[3]);
00403
00404 theta.push_back(new colvar::dihedral(cvm::atom(r[i ], "C", sid),
00405 cvm::atom(r[i+1], "N", sid),
00406 cvm::atom(r[i+1], "CA", sid),
00407 cvm::atom(r[i+1], "C", sid)));
00408 register_atom_group(theta.back()->atom_groups[0]);
00409 register_atom_group(theta.back()->atom_groups[1]);
00410 register_atom_group(theta.back()->atom_groups[2]);
00411 register_atom_group(theta.back()->atom_groups[3]);
00412 }
00413
00414 if (cvm::debug())
00415 cvm::log("Done initializing dihedPC object.\n");
00416 }
00417
00418
00419 colvar::dihedPC::dihedPC()
00420 : cvc()
00421 {
00422 set_function_type("dihedPC");
00423
00424 enable(f_cvc_explicit_gradient);
00425 x.type(colvarvalue::type_scalar);
00426 }
00427
00428
00429 colvar::dihedPC::~dihedPC()
00430 {
00431 while (theta.size() != 0) {
00432 delete theta.back();
00433 theta.pop_back();
00434 }
00435
00436 atom_groups.clear();
00437 }
00438
00439
00440 void colvar::dihedPC::calc_value()
00441 {
00442 x.real_value = 0.0;
00443 for (size_t i = 0; i < theta.size(); i++) {
00444 theta[i]->calc_value();
00445 cvm::real const t = (PI / 180.) * theta[i]->value().real_value;
00446 x.real_value += coeffs[2*i ] * cvm::cos(t)
00447 + coeffs[2*i+1] * cvm::sin(t);
00448 }
00449 }
00450
00451
00452 void colvar::dihedPC::calc_gradients()
00453 {
00454 for (size_t i = 0; i < theta.size(); i++) {
00455 theta[i]->calc_gradients();
00456 }
00457 }
00458
00459
00460 void colvar::dihedPC::collect_gradients(std::vector<int> const &atom_ids, std::vector<cvm::rvector> &atomic_gradients)
00461 {
00462 cvm::real cvc_coeff = sup_coeff * cvm::real(sup_np) * cvm::integer_power(value().real_value, sup_np-1);
00463 for (size_t i = 0; i < theta.size(); i++) {
00464 cvm::real const t = (PI / 180.) * theta[i]->value().real_value;
00465 cvm::real const dcosdt = - (PI / 180.) * cvm::sin(t);
00466 cvm::real const dsindt = (PI / 180.) * cvm::cos(t);
00467
00468
00469 cvm::real const coeff = cvc_coeff * (coeffs[2*i] * dcosdt + coeffs[2*i+1] * dsindt);
00470
00471 for (size_t j = 0; j < theta[i]->atom_groups.size(); j++) {
00472 cvm::atom_group &ag = *(theta[i]->atom_groups[j]);
00473 for (size_t k = 0; k < ag.size(); k++) {
00474 size_t a = std::lower_bound(atom_ids.begin(), atom_ids.end(),
00475 ag[k].id) - atom_ids.begin();
00476 atomic_gradients[a] += coeff * ag[k].grad;
00477 }
00478 }
00479 }
00480 }
00481
00482
00483 void colvar::dihedPC::apply_force(colvarvalue const &force)
00484 {
00485 for (size_t i = 0; i < theta.size(); i++) {
00486 cvm::real const t = (PI / 180.) * theta[i]->value().real_value;
00487 cvm::real const dcosdt = - (PI / 180.) * cvm::sin(t);
00488 cvm::real const dsindt = (PI / 180.) * cvm::cos(t);
00489
00490 theta[i]->apply_force((coeffs[2*i ] * dcosdt +
00491 coeffs[2*i+1] * dsindt) * force);
00492 }
00493 }
00494
00495
00496 simple_scalar_dist_functions(dihedPC)