Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

colvarbias_restraint.C

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 
00003 // This file is part of the Collective Variables module (Colvars).
00004 // The original version of Colvars and its updates are located at:
00005 // https://github.com/Colvars/colvars
00006 // Please update all Colvars source files before making any changes.
00007 // If you wish to distribute your changes, please submit them to the
00008 // Colvars repository at GitHub.
00009 
00010 #include <fstream>
00011 #include <iostream>
00012 #include <iomanip>
00013 
00014 #include "colvarmodule.h"
00015 #include "colvarproxy.h"
00016 #include "colvarvalue.h"
00017 #include "colvarbias_restraint.h"
00018 
00019 
00020 
00021 colvarbias_restraint::colvarbias_restraint(char const *key)
00022   : colvarbias(key), colvarbias_ti(key)
00023 {
00024   state_keyword = "restraint";
00025 }
00026 
00027 
00028 int colvarbias_restraint::init(std::string const &conf)
00029 {
00030   colvarbias::init(conf);
00031   enable(f_cvb_apply_force);
00032 
00033   colvarbias_ti::init(conf);
00034 
00035   if (cvm::debug())
00036     cvm::log("Initializing a new restraint bias.\n");
00037 
00038   return COLVARS_OK;
00039 }
00040 
00041 
00042 int colvarbias_restraint::update()
00043 {
00044   // Update base class (bias_energy and colvar_forces are zeroed there)
00045   colvarbias::update();
00046 
00047   // Force and energy calculation
00048   for (size_t i = 0; i < num_variables(); i++) {
00049     bias_energy += restraint_potential(i);
00050     colvar_forces[i].type(variables(i)->value());
00051     colvar_forces[i].is_derivative();
00052     colvar_forces[i] = restraint_force(i);
00053   }
00054 
00055   if (cvm::debug())
00056     cvm::log("Done updating the restraint bias \""+this->name+"\".\n");
00057 
00058   if (cvm::debug())
00059     cvm::log("Current forces for the restraint bias \""+
00060              this->name+"\": "+cvm::to_str(colvar_forces)+".\n");
00061 
00062   return COLVARS_OK;
00063 }
00064 
00065 
00066 colvarbias_restraint::~colvarbias_restraint()
00067 {
00068 }
00069 
00070 
00071 std::string const colvarbias_restraint::get_state_params() const
00072 {
00073   return colvarbias::get_state_params();
00074 }
00075 
00076 
00077 int colvarbias_restraint::set_state_params(std::string const &conf)
00078 {
00079   return colvarbias::set_state_params(conf);
00080 }
00081 
00082 
00083 std::ostream & colvarbias_restraint::write_traj_label(std::ostream &os)
00084 {
00085   return colvarbias::write_traj_label(os);
00086 }
00087 
00088 
00089 std::ostream & colvarbias_restraint::write_traj(std::ostream &os)
00090 {
00091   return colvarbias::write_traj(os);
00092 }
00093 
00094 
00095 
00096 colvarbias_restraint_centers::colvarbias_restraint_centers(char const *key)
00097   : colvarbias(key), colvarbias_ti(key), colvarbias_restraint(key)
00098 {
00099 }
00100 
00101 
00102 int colvarbias_restraint_centers::init(std::string const &conf)
00103 {
00104   size_t i;
00105 
00106   bool null_centers = (colvar_centers.size() == 0);
00107   if (null_centers) {
00108     // try to initialize the restraint centers for the first time
00109     colvar_centers.resize(num_variables());
00110     for (i = 0; i < num_variables(); i++) {
00111       colvar_centers[i].type(variables(i)->value());
00112       colvar_centers[i].reset();
00113     }
00114   }
00115 
00116   if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
00117     for (i = 0; i < num_variables(); i++) {
00118       if (cvm::debug()) {
00119         cvm::log("colvarbias_restraint: parsing initial centers, i = "+cvm::to_str(i)+".\n");
00120       }
00121       colvar_centers[i].apply_constraints();
00122     }
00123     null_centers = false;
00124   }
00125 
00126   if (null_centers) {
00127     colvar_centers.clear();
00128     cvm::error("Error: must define the initial centers of the restraints.\n", COLVARS_INPUT_ERROR);
00129     return COLVARS_INPUT_ERROR;
00130   }
00131 
00132   if (colvar_centers.size() != num_variables()) {
00133     cvm::error("Error: number of centers does not match "
00134                "that of collective variables.\n", COLVARS_INPUT_ERROR);
00135     return COLVARS_INPUT_ERROR;
00136   }
00137 
00138   return COLVARS_OK;
00139 }
00140 
00141 
00142 int colvarbias_restraint_centers::change_configuration(std::string const &conf)
00143 {
00144   if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) {
00145     for (size_t i = 0; i < num_variables(); i++) {
00146       colvar_centers[i].type(variables(i)->value());
00147       colvar_centers[i].apply_constraints();
00148     }
00149   }
00150   return COLVARS_OK;
00151 }
00152 
00153 
00154 
00155 colvarbias_restraint_k::colvarbias_restraint_k(char const *key)
00156   : colvarbias(key), colvarbias_ti(key), colvarbias_restraint(key)
00157 {
00158   force_k = -1.0;
00159   check_positive_k = true;
00160 }
00161 
00162 
00163 int colvarbias_restraint_k::init(std::string const &conf)
00164 {
00165   get_keyval(conf, "forceConstant", force_k, (force_k > 0.0 ? force_k : 1.0));
00166   if (check_positive_k && (force_k < 0.0)) {
00167     cvm::error("Error: undefined or invalid force constant.\n", COLVARS_INPUT_ERROR);
00168     return COLVARS_INPUT_ERROR;
00169   }
00170   return COLVARS_OK;
00171 }
00172 
00173 
00174 int colvarbias_restraint_k::change_configuration(std::string const &conf)
00175 {
00176   get_keyval(conf, "forceConstant", force_k, force_k);
00177   return COLVARS_OK;
00178 }
00179 
00180 
00181 
00182 colvarbias_restraint_moving::colvarbias_restraint_moving(char const * /* key */)
00183 {
00184   target_nstages = 0;
00185   target_nsteps = 0L;
00186   stage = 0;
00187   acc_work = 0.0;
00188   b_chg_centers = false;
00189   b_chg_force_k = false;
00190 }
00191 
00192 
00193 int colvarbias_restraint_moving::init(std::string const &conf)
00194 {
00195   if (b_chg_centers && b_chg_force_k) {
00196     cvm::error("Error: cannot specify both targetCenters and targetForceConstant.\n",
00197                COLVARS_INPUT_ERROR);
00198     return COLVARS_INPUT_ERROR;
00199   }
00200 
00201   if (b_chg_centers || b_chg_force_k) {
00202 
00203     first_step = cvm::step_absolute();
00204 
00205     get_keyval(conf, "targetNumSteps", target_nsteps, target_nsteps);
00206     if (!target_nsteps) {
00207       cvm::error("Error: targetNumSteps must be non-zero.\n", COLVARS_INPUT_ERROR);
00208       return cvm::get_error();
00209     }
00210 
00211     if (get_keyval(conf, "targetNumStages", target_nstages, target_nstages) &&
00212         lambda_schedule.size()) {
00213       cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", COLVARS_INPUT_ERROR);
00214       return cvm::get_error();
00215     }
00216 
00217     get_keyval_feature(this, conf, "outputAccumulatedWork",
00218                        f_cvb_output_acc_work,
00219                        is_enabled(f_cvb_output_acc_work));
00220     if (is_enabled(f_cvb_output_acc_work) && (target_nstages > 0)) {
00221       return cvm::error("Error: outputAccumulatedWork and targetNumStages "
00222                         "are incompatible.\n", COLVARS_INPUT_ERROR);
00223     }
00224   }
00225 
00226   return COLVARS_OK;
00227 }
00228 
00229 
00230 std::string const colvarbias_restraint_moving::get_state_params() const
00231 {
00232   std::ostringstream os;
00233   os.setf(std::ios::scientific, std::ios::floatfield);
00234   if (b_chg_centers || b_chg_force_k) {
00235     // TODO move this
00236     if (target_nstages) {
00237       os << "stage " << std::setw(cvm::it_width)
00238          << stage << "\n";
00239     }
00240   }
00241   return os.str();
00242 }
00243 
00244 
00245 int colvarbias_restraint_moving::set_state_params(std::string const &conf)
00246 {
00247   if (b_chg_centers || b_chg_force_k) {
00248     if (target_nstages) {
00249       get_keyval(conf, "stage", stage, stage,
00250                  colvarparse::parse_restart | colvarparse::parse_required);
00251     }
00252   }
00253   return COLVARS_OK;
00254 }
00255 
00256 
00257 
00258 colvarbias_restraint_centers_moving::colvarbias_restraint_centers_moving(char const *key)
00259   : colvarbias(key),
00260     colvarbias_ti(key),
00261     colvarbias_restraint(key),
00262     colvarbias_restraint_centers(key),
00263     colvarbias_restraint_moving(key)
00264 {
00265   b_chg_centers = false;
00266   b_output_centers = false;
00267 }
00268 
00269 
00270 int colvarbias_restraint_centers_moving::init(std::string const &conf)
00271 {
00272   colvarbias_restraint_centers::init(conf);
00273 
00274   if (cvm::debug()) {
00275     cvm::log("colvarbias_restraint: parsing target centers.\n");
00276   }
00277 
00278   size_t i;
00279   if (get_keyval(conf, "targetCenters", target_centers, colvar_centers)) {
00280     if (target_centers.size() != num_variables()) {
00281       cvm::error("Error: number of target centers does not match "
00282                  "that of collective variables.\n", COLVARS_INPUT_ERROR);
00283     }
00284     b_chg_centers = true;
00285     for (i = 0; i < target_centers.size(); i++) {
00286       target_centers[i].apply_constraints();
00287       centers_incr.push_back(colvar_centers[i]);
00288       centers_incr[i].reset();
00289     }
00290   }
00291 
00292   if (b_chg_centers) {
00293     // parse moving schedule options
00294     colvarbias_restraint_moving::init(conf);
00295     if (initial_centers.size() == 0) {
00296       // One-time init
00297       initial_centers = colvar_centers;
00298     }
00299     // Call to check that the definition is correct
00300     for (i = 0; i < num_variables(); i++) {
00301       colvarvalue const midpoint =
00302         colvarvalue::interpolate(initial_centers[i],
00303                                  target_centers[i],
00304                                  0.5);
00305     }
00306 
00307   } else {
00308     target_centers.clear();
00309   }
00310 
00311   // Output restraint centers even when they do not change; some NAMD REUS
00312   // scripts expect this behavior
00313   get_keyval(conf, "outputCenters", b_output_centers, b_output_centers);
00314 
00315   return COLVARS_OK;
00316 }
00317 
00318 
00319 int colvarbias_restraint_centers_moving::update_centers(cvm::real lambda)
00320 {
00321   if (cvm::debug()) {
00322     cvm::log("Updating centers for the restraint bias \""+
00323              this->name+"\": "+cvm::to_str(colvar_centers)+".\n");
00324   }
00325   size_t i;
00326   for (i = 0; i < num_variables(); i++) {
00327     colvarvalue const c_new = colvarvalue::interpolate(initial_centers[i],
00328                                                        target_centers[i],
00329                                                        lambda);
00330     centers_incr[i] = 0.5 * c_new.dist2_grad(colvar_centers[i]);
00331     colvar_centers[i] = c_new;
00332     variables(i)->wrap(colvar_centers[i]);
00333   }
00334   if (cvm::debug()) {
00335     cvm::log("New centers for the restraint bias \""+
00336              this->name+"\": "+cvm::to_str(colvar_centers)+".\n");
00337   }
00338   return cvm::get_error();
00339 }
00340 
00341 
00342 int colvarbias_restraint_centers_moving::update()
00343 {
00344   if (!cvm::main()->proxy->simulation_running()) {
00345     return COLVARS_OK;
00346   }
00347 
00348   if (b_chg_centers) {
00349 
00350     if (target_nstages) {
00351       // Staged update
00352       if (stage <= target_nstages) {
00353         if ((cvm::step_relative() > 0) &&
00354             (((cvm::step_absolute() - first_step) % target_nsteps) == 1)) {
00355           cvm::real const lambda =
00356             cvm::real(stage)/cvm::real(target_nstages);
00357           update_centers(lambda);
00358           stage++;
00359           cvm::log("Moving restraint \"" + this->name +
00360                    "\" stage " + cvm::to_str(stage) +
00361                    " : setting centers to " + cvm::to_str(colvar_centers) +
00362                    " at step " +  cvm::to_str(cvm::step_absolute()));
00363         } else {
00364           for (size_t i = 0; i < num_variables(); i++) {
00365             centers_incr[i].reset();
00366           }
00367         }
00368       }
00369     } else {
00370       // Continuous update
00371       if (cvm::step_absolute() - first_step <= target_nsteps) {
00372         cvm::real const lambda =
00373           cvm::real(cvm::step_absolute() - first_step)/cvm::real(target_nsteps);
00374         update_centers(lambda);
00375       } else {
00376         for (size_t i = 0; i < num_variables(); i++) {
00377           centers_incr[i].reset();
00378         }
00379       }
00380     }
00381 
00382     if (cvm::step_relative() == 0) {
00383       for (size_t i = 0; i < num_variables(); i++) {
00384         // finite differences are undefined when restarting
00385         centers_incr[i].reset();
00386       }
00387     }
00388 
00389     if (cvm::debug()) {
00390       cvm::log("Center increment for the restraint bias \""+
00391                this->name+"\": "+cvm::to_str(centers_incr)+
00392                " at stage "+cvm::to_str(stage)+ ".\n");
00393     }
00394   }
00395 
00396   return cvm::get_error();
00397 }
00398 
00399 
00400 int colvarbias_restraint_centers_moving::update_acc_work()
00401 {
00402   if (!cvm::main()->proxy->simulation_running()) {
00403     return COLVARS_OK;
00404   }
00405   if (b_chg_centers) {
00406     if (is_enabled(f_cvb_output_acc_work)) {
00407       if ((cvm::step_relative() > 0) &&
00408           (cvm::step_absolute() - first_step <= target_nsteps)) {
00409         for (size_t i = 0; i < num_variables(); i++) {
00410           // project forces on the calculated increments at this step
00411           acc_work += colvar_forces[i] * centers_incr[i];
00412         }
00413       }
00414     }
00415   }
00416   return COLVARS_OK;
00417 }
00418 
00419 
00420 std::string const colvarbias_restraint_centers_moving::get_state_params() const
00421 {
00422   std::ostringstream os;
00423   os.setf(std::ios::scientific, std::ios::floatfield);
00424 
00425   if (b_chg_centers) {
00426     size_t i;
00427     os << "centers ";
00428     for (i = 0; i < num_variables(); i++) {
00429       os << " "
00430          << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
00431          << colvar_centers[i];
00432     }
00433     os << "\n";
00434 
00435     if (is_enabled(f_cvb_output_acc_work)) {
00436       os << "accumulatedWork "
00437          << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
00438          << acc_work << "\n";
00439     }
00440   }
00441 
00442   return os.str();
00443 }
00444 
00445 
00446 int colvarbias_restraint_centers_moving::set_state_params(std::string const &conf)
00447 {
00448   colvarbias_restraint::set_state_params(conf);
00449 
00450   if (b_chg_centers) {
00451     get_keyval(conf, "centers", colvar_centers, colvar_centers,
00452                colvarparse::parse_restart | colvarparse::parse_required);
00453   }
00454 
00455   if (is_enabled(f_cvb_output_acc_work)) {
00456     get_keyval(conf, "accumulatedWork", acc_work, acc_work,
00457                colvarparse::parse_restart | colvarparse::parse_required);
00458   }
00459 
00460   return COLVARS_OK;
00461 }
00462 
00463 
00464 std::ostream & colvarbias_restraint_centers_moving::write_traj_label(std::ostream &os)
00465 {
00466   if (b_output_centers) {
00467     for (size_t i = 0; i < num_variables(); i++) {
00468       size_t const this_cv_width = (variables(i)->value()).output_width(cvm::cv_width);
00469       os << " x0_"
00470          << cvm::wrap_string(variables(i)->name, this_cv_width-3);
00471     }
00472   }
00473 
00474   if (b_chg_centers && is_enabled(f_cvb_output_acc_work)) {
00475     os << " W_"
00476        << cvm::wrap_string(this->name, cvm::en_width-2);
00477   }
00478 
00479   return os;
00480 }
00481 
00482 
00483 std::ostream & colvarbias_restraint_centers_moving::write_traj(std::ostream &os)
00484 {
00485   if (b_output_centers) {
00486     for (size_t i = 0; i < num_variables(); i++) {
00487       os << " "
00488          << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width)
00489          << colvar_centers[i];
00490     }
00491   }
00492 
00493   if (b_chg_centers && is_enabled(f_cvb_output_acc_work)) {
00494     os << " "
00495        << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
00496        << acc_work;
00497   }
00498 
00499   return os;
00500 }
00501 
00502 
00503 
00504 colvarbias_restraint_k_moving::colvarbias_restraint_k_moving(char const *key)
00505   : colvarbias(key),
00506     colvarbias_ti(key),
00507     colvarbias_restraint(key),
00508     colvarbias_restraint_k(key),
00509     colvarbias_restraint_moving(key)
00510 {
00511   b_chg_force_k = false;
00512   b_decoupling = false;
00513   target_equil_steps = 0;
00514   target_force_k = -1.0;
00515   starting_force_k = -1.0;
00516   lambda_exp = 1.0;
00517   restraint_FE = 0.0;
00518   force_k_incr = 0.0;
00519 }
00520 
00521 
00522 int colvarbias_restraint_k_moving::init(std::string const &conf)
00523 {
00524   colvarbias_restraint_k::init(conf);
00525 
00526   get_keyval(conf, "decoupling", b_decoupling, b_decoupling);
00527   if (b_decoupling) {
00528     starting_force_k = 0.0;
00529     target_force_k = force_k;
00530     b_chg_force_k = true;
00531   }
00532 
00533   if (get_keyval(conf, "targetForceConstant", target_force_k, target_force_k)) {
00534     if (b_decoupling) {
00535       cvm::error("Error: targetForceConstant may not be specified together with decoupling.\n", COLVARS_INPUT_ERROR);
00536       return COLVARS_ERROR;
00537     }
00538     starting_force_k = force_k;
00539     b_chg_force_k = true;
00540   }
00541 
00542   if (!b_chg_force_k) {
00543     return COLVARS_OK;
00544   }
00545 
00546   // parse moving restraint options
00547   colvarbias_restraint_moving::init(conf);
00548 
00549   get_keyval(conf, "targetEquilSteps", target_equil_steps, target_equil_steps);
00550 
00551   if (get_keyval(conf, "lambdaSchedule", lambda_schedule, lambda_schedule) &&
00552       target_nstages > 0) {
00553     cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n", COLVARS_INPUT_ERROR);
00554     return cvm::get_error();
00555   }
00556 
00557   if (lambda_schedule.size()) {
00558     // There is one more lambda-point than stages
00559     target_nstages = lambda_schedule.size() - 1;
00560   }
00561 
00562   if ((get_keyval(conf, "targetForceExponent", lambda_exp, lambda_exp, parse_deprecated)
00563     || get_keyval(conf, "lambdaExponent", lambda_exp, lambda_exp))
00564     && !b_chg_force_k) {
00565     cvm::error("Error: cannot set lambdaExponent unless a changing force constant is active.\n", COLVARS_INPUT_ERROR);
00566   }
00567   if (lambda_exp < 1.0) {
00568     cvm::log("Warning: for all practical purposes, lambdaExponent should be 1.0 or greater.\n");
00569   }
00570 
00571   return COLVARS_OK;
00572 }
00573 
00574 
00575 int colvarbias_restraint_k_moving::update()
00576 {
00577   if (!cvm::main()->proxy->simulation_running()) {
00578     return COLVARS_OK;
00579   }
00580   if (b_chg_force_k) {
00581 
00582     cvm::real lambda;
00583 
00584     if (target_nstages) {
00585 
00586       if (cvm::step_absolute() == first_step) {
00587         // Setup first stage of staged variable force constant calculation
00588         if (lambda_schedule.size()) {
00589           lambda = lambda_schedule[0];
00590         } else {
00591           lambda = (b_decoupling ? 1.0 : 0.0);
00592         }
00593         force_k = starting_force_k + (target_force_k - starting_force_k)
00594           * cvm::pow(lambda, lambda_exp);
00595           cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage)
00596                   + " : lambda = " + cvm::to_str(lambda)
00597                   + ", k = " + cvm::to_str(force_k)+"\n");
00598       }
00599 
00600       // TI calculation: estimate free energy derivative
00601       // need current lambda
00602       if (lambda_schedule.size()) {
00603         lambda = lambda_schedule[stage];
00604       } else {
00605         lambda = cvm::real(stage) / cvm::real(target_nstages);
00606         if (b_decoupling) lambda = 1.0 - lambda;
00607       }
00608 
00609       if (target_equil_steps == 0 || (cvm::step_absolute() - first_step) % target_nsteps >= target_equil_steps) {
00610         // Start averaging after equilibration period, if requested
00611 
00612         // Derivative of energy with respect to force_k
00613         cvm::real dU_dk = 0.0;
00614         for (size_t i = 0; i < num_variables(); i++) {
00615           dU_dk += d_restraint_potential_dk(i);
00616         }
00617         restraint_FE += lambda_exp * cvm::pow(lambda, lambda_exp - 1.0)
00618           * (target_force_k - starting_force_k) * dU_dk;
00619       }
00620 
00621       // Finish current stage...
00622       if ((cvm::step_absolute() - first_step) % target_nsteps == 0 &&
00623            cvm::step_absolute() > first_step) {
00624 
00625         cvm::log("Restraint " + this->name + " Lambda= "
00626                  + cvm::to_str(lambda) + " dA/dLambda= "
00627                  + cvm::to_str(restraint_FE / cvm::real(target_nsteps - target_equil_steps))+"\n");
00628 
00629         //  ...and move on to the next one
00630         if (stage < target_nstages) {
00631 
00632           restraint_FE = 0.0;
00633           stage++;
00634           if (lambda_schedule.size()) {
00635             lambda = lambda_schedule[stage];
00636           } else {
00637             lambda = cvm::real(stage) / cvm::real(target_nstages);
00638             if (b_decoupling) lambda = 1.0 - lambda;
00639           }
00640           force_k = starting_force_k + (target_force_k - starting_force_k)
00641             * cvm::pow(lambda, lambda_exp);
00642           cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage)
00643                   + " : lambda = " + cvm::to_str(lambda)
00644                   + ", k = " + cvm::to_str(force_k)+"\n");
00645         }
00646       }
00647 
00648     } else if (cvm::step_absolute() - first_step <= target_nsteps) {
00649 
00650       // update force constant (slow growth)
00651       lambda = cvm::real(cvm::step_absolute() - first_step) / cvm::real(target_nsteps);
00652       if (b_decoupling) lambda = 1.0 - lambda;
00653       cvm::real const force_k_old = force_k;
00654       force_k = starting_force_k + (target_force_k - starting_force_k)
00655         * cvm::pow(lambda, lambda_exp);
00656       force_k_incr = force_k - force_k_old;
00657     }
00658   }
00659 
00660   return COLVARS_OK;
00661 }
00662 
00663 
00664 int colvarbias_restraint_k_moving::update_acc_work()
00665 {
00666   if (!cvm::main()->proxy->simulation_running()) {
00667     return COLVARS_OK;
00668   }
00669   if (b_chg_force_k) {
00670     if (is_enabled(f_cvb_output_acc_work)) {
00671       if (cvm::step_relative() > 0) {
00672         cvm::real dU_dk = 0.0;
00673         for (size_t i = 0; i < num_variables(); i++) {
00674           dU_dk += d_restraint_potential_dk(i);
00675         }
00676         acc_work += dU_dk * force_k_incr;
00677       }
00678     }
00679   }
00680   return COLVARS_OK;
00681 }
00682 
00683 
00684 std::string const colvarbias_restraint_k_moving::get_state_params() const
00685 {
00686   std::ostringstream os;
00687   os.setf(std::ios::scientific, std::ios::floatfield);
00688   if (b_chg_force_k) {
00689     os << "forceConstant "
00690        << std::setprecision(cvm::en_prec)
00691        << std::setw(cvm::en_width) << force_k << "\n";
00692 
00693     if (is_enabled(f_cvb_output_acc_work)) {
00694       os << "accumulatedWork "
00695          << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
00696          << acc_work << "\n";
00697     }
00698   }
00699   return os.str();
00700 }
00701 
00702 
00703 int colvarbias_restraint_k_moving::set_state_params(std::string const &conf)
00704 {
00705   colvarbias_restraint::set_state_params(conf);
00706 
00707   if (b_chg_force_k) {
00708     get_keyval(conf, "forceConstant", force_k, force_k,
00709                colvarparse::parse_restart | colvarparse::parse_required);
00710   }
00711 
00712   if (is_enabled(f_cvb_output_acc_work)) {
00713     get_keyval(conf, "accumulatedWork", acc_work, acc_work,
00714                colvarparse::parse_restart | colvarparse::parse_required);
00715   }
00716 
00717   return COLVARS_OK;
00718 }
00719 
00720 
00721 std::ostream & colvarbias_restraint_k_moving::write_traj_label(std::ostream &os)
00722 {
00723   if (b_chg_force_k && is_enabled(f_cvb_output_acc_work)) {
00724     os << " W_"
00725        << cvm::wrap_string(this->name, cvm::en_width-2);
00726   }
00727   return os;
00728 }
00729 
00730 
00731 std::ostream & colvarbias_restraint_k_moving::write_traj(std::ostream &os)
00732 {
00733   if (b_chg_force_k && is_enabled(f_cvb_output_acc_work)) {
00734     os << " "
00735        << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
00736        << acc_work;
00737   }
00738   return os;
00739 }
00740 
00741 
00742 
00743 colvarbias_restraint_harmonic::colvarbias_restraint_harmonic(char const *key)
00744   : colvarbias(key),
00745     colvarbias_ti(key),
00746     colvarbias_restraint(key),
00747     colvarbias_restraint_centers(key),
00748     colvarbias_restraint_moving(key),
00749     colvarbias_restraint_k(key),
00750     colvarbias_restraint_centers_moving(key),
00751     colvarbias_restraint_k_moving(key)
00752 {
00753 }
00754 
00755 
00756 int colvarbias_restraint_harmonic::init(std::string const &conf)
00757 {
00758   colvarbias_restraint::init(conf);
00759   colvarbias_restraint_moving::init(conf);
00760   colvarbias_restraint_centers_moving::init(conf);
00761   colvarbias_restraint_k_moving::init(conf);
00762 
00763   cvm::main()->cite_feature("Harmonic colvar bias implementation");
00764 
00765   for (size_t i = 0; i < num_variables(); i++) {
00766     cvm::real const w = variables(i)->width;
00767     cvm::log("The force constant for colvar \""+variables(i)->name+
00768              "\" will be rescaled to "+
00769              cvm::to_str(force_k/(w*w))+
00770              " according to the specified width ("+cvm::to_str(w)+").\n");
00771   }
00772 
00773   return COLVARS_OK;
00774 }
00775 
00776 
00777 int colvarbias_restraint_harmonic::update()
00778 {
00779   int error_code = COLVARS_OK;
00780 
00781   // update the TI estimator (if defined)
00782   error_code |= colvarbias_ti::update();
00783 
00784   // update parameters (centers or force constant)
00785   error_code |= colvarbias_restraint_centers_moving::update();
00786   error_code |= colvarbias_restraint_k_moving::update();
00787 
00788   // update restraint energy and forces
00789   error_code |= colvarbias_restraint::update();
00790 
00791   // update accumulated work using the current forces
00792   error_code |= colvarbias_restraint_centers_moving::update_acc_work();
00793   error_code |= colvarbias_restraint_k_moving::update_acc_work();
00794 
00795   return error_code;
00796 }
00797 
00798 
00799 cvm::real colvarbias_restraint_harmonic::restraint_potential(size_t i) const
00800 {
00801   return 0.5 * force_k / (variables(i)->width * variables(i)->width) *
00802     variables(i)->dist2(variables(i)->value(), colvar_centers[i]);
00803 }
00804 
00805 
00806 colvarvalue const colvarbias_restraint_harmonic::restraint_force(size_t i) const
00807 {
00808   return -0.5 * force_k / (variables(i)->width * variables(i)->width) *
00809     variables(i)->dist2_lgrad(variables(i)->value(), colvar_centers[i]);
00810 }
00811 
00812 
00813 cvm::real colvarbias_restraint_harmonic::d_restraint_potential_dk(size_t i) const
00814 {
00815   return 0.5 / (variables(i)->width * variables(i)->width) *
00816     variables(i)->dist2(variables(i)->value(), colvar_centers[i]);
00817 }
00818 
00819 
00820 std::string const colvarbias_restraint_harmonic::get_state_params() const
00821 {
00822   return colvarbias_restraint::get_state_params() +
00823     colvarbias_restraint_moving::get_state_params() +
00824     colvarbias_restraint_centers_moving::get_state_params() +
00825     colvarbias_restraint_k_moving::get_state_params();
00826 }
00827 
00828 
00829 int colvarbias_restraint_harmonic::set_state_params(std::string const &conf)
00830 {
00831   int error_code = COLVARS_OK;
00832   error_code |= colvarbias_restraint::set_state_params(conf);
00833   error_code |= colvarbias_restraint_moving::set_state_params(conf);
00834   error_code |= colvarbias_restraint_centers_moving::set_state_params(conf);
00835   error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
00836   return error_code;
00837 }
00838 
00839 
00840 std::ostream & colvarbias_restraint_harmonic::write_state_data(std::ostream &os)
00841 {
00842   return colvarbias_ti::write_state_data(os);
00843 }
00844 
00845 
00846 std::istream & colvarbias_restraint_harmonic::read_state_data(std::istream &is)
00847 {
00848   return colvarbias_ti::read_state_data(is);
00849 }
00850 
00851 
00852 std::ostream & colvarbias_restraint_harmonic::write_traj_label(std::ostream &os)
00853 {
00854   colvarbias_restraint::write_traj_label(os);
00855   colvarbias_restraint_centers_moving::write_traj_label(os);
00856   colvarbias_restraint_k_moving::write_traj_label(os);
00857   return os;
00858 }
00859 
00860 
00861 std::ostream & colvarbias_restraint_harmonic::write_traj(std::ostream &os)
00862 {
00863   colvarbias_restraint::write_traj(os);
00864   colvarbias_restraint_centers_moving::write_traj(os);
00865   colvarbias_restraint_k_moving::write_traj(os);
00866   return os;
00867 }
00868 
00869 
00870 int colvarbias_restraint_harmonic::change_configuration(std::string const &conf)
00871 {
00872   return colvarbias_restraint_centers::change_configuration(conf) |
00873     colvarbias_restraint_k::change_configuration(conf);
00874 }
00875 
00876 
00877 cvm::real colvarbias_restraint_harmonic::energy_difference(std::string const &conf)
00878 {
00879   cvm::real const old_bias_energy = bias_energy;
00880   cvm::real const old_force_k = force_k;
00881   std::vector<colvarvalue> const old_centers = colvar_centers;
00882 
00883   change_configuration(conf);
00884   update();
00885 
00886   cvm::real const result = (bias_energy - old_bias_energy);
00887 
00888   bias_energy = old_bias_energy;
00889   force_k = old_force_k;
00890   colvar_centers = old_centers;
00891 
00892   return result;
00893 }
00894 
00895 
00896 
00897 colvarbias_restraint_harmonic_walls::colvarbias_restraint_harmonic_walls(char const *key)
00898   : colvarbias(key),
00899     colvarbias_ti(key),
00900     colvarbias_restraint(key),
00901     colvarbias_restraint_k(key),
00902     colvarbias_restraint_moving(key),
00903     colvarbias_restraint_k_moving(key)
00904 {
00905   lower_wall_k = -1.0;
00906   upper_wall_k = -1.0;
00907   // This bias implements the bias_actual_colvars feature (most others do not)
00908   provide(f_cvb_bypass_ext_lagrangian);
00909   set_enabled(f_cvb_bypass_ext_lagrangian); // Defaults to enabled
00910 }
00911 
00912 
00913 int colvarbias_restraint_harmonic_walls::init(std::string const &conf)
00914 {
00915   colvarbias_restraint::init(conf);
00916   colvarbias_restraint_moving::init(conf);
00917   colvarbias_restraint_k_moving::init(conf);
00918 
00919   cvm::main()->cite_feature("harmonicWalls colvar bias implementation");
00920 
00921   enable(f_cvb_scalar_variables);
00922 
00923   size_t i;
00924 
00925   bool b_null_lower_walls = false;
00926   if (lower_walls.size() == 0) {
00927     b_null_lower_walls = true;
00928     lower_walls.resize(num_variables());
00929     for (i = 0; i < num_variables(); i++) {
00930       lower_walls[i].type(variables(i)->value());
00931       lower_walls[i].reset();
00932     }
00933   }
00934   if (!get_keyval(conf, "lowerWalls", lower_walls, lower_walls) &&
00935       b_null_lower_walls) {
00936     cvm::log("Lower walls were not provided.\n");
00937     lower_walls.clear();
00938   }
00939 
00940   bool b_null_upper_walls = false;
00941   if (upper_walls.size() == 0) {
00942     b_null_upper_walls = true;
00943     upper_walls.resize(num_variables());
00944     for (i = 0; i < num_variables(); i++) {
00945       upper_walls[i].type(variables(i)->value());
00946       upper_walls[i].reset();
00947     }
00948   }
00949   if (!get_keyval(conf, "upperWalls", upper_walls, upper_walls) &&
00950       b_null_upper_walls) {
00951     cvm::log("Upper walls were not provided.\n");
00952     upper_walls.clear();
00953   }
00954 
00955   if ((lower_walls.size() == 0) && (upper_walls.size() == 0)) {
00956     return cvm::error("Error: no walls provided.\n", COLVARS_INPUT_ERROR);
00957   }
00958 
00959   if (lower_walls.size() > 0) {
00960     get_keyval(conf, "lowerWallConstant", lower_wall_k,
00961                (lower_wall_k > 0.0) ? lower_wall_k : force_k);
00962   }
00963   if (upper_walls.size() > 0) {
00964     get_keyval(conf, "upperWallConstant", upper_wall_k,
00965                (upper_wall_k > 0.0) ? upper_wall_k : force_k);
00966   }
00967 
00968   if ((lower_walls.size() == 0) || (upper_walls.size() == 0)) {
00969     for (i = 0; i < num_variables(); i++) {
00970       if (variables(i)->is_enabled(f_cv_periodic)) {
00971         return cvm::error("Error: at least one variable is periodic, "
00972                           "both walls must be provided.\n", COLVARS_INPUT_ERROR);
00973       }
00974     }
00975   }
00976 
00977   if ((lower_walls.size() > 0) && (upper_walls.size() > 0)) {
00978     for (i = 0; i < num_variables(); i++) {
00979       if (lower_walls[i] >= upper_walls[i]) {
00980         return cvm::error("Error: one upper wall, "+
00981                           cvm::to_str(upper_walls[i])+
00982                           ", is not higher than the lower wall, "+
00983                           cvm::to_str(lower_walls[i])+".\n",
00984                           COLVARS_INPUT_ERROR);
00985       }
00986       if (variables(i)->dist2(lower_walls[i], upper_walls[i]) < 1.0e-12) {
00987         return cvm::error("Error: lower wall and upper wall are equal "
00988                           "in the domain of the variable \""+
00989                           variables(i)->name+"\".\n", COLVARS_INPUT_ERROR);
00990       }
00991     }
00992     if (lower_wall_k * upper_wall_k == 0.0) {
00993       cvm::error("Error: lowerWallConstant and upperWallConstant, "
00994                  "when defined, must both be positive.\n",
00995                  COLVARS_INPUT_ERROR);
00996       return COLVARS_INPUT_ERROR;
00997     }
00998     force_k = cvm::sqrt(lower_wall_k * upper_wall_k);
00999     // transform the two constants to relative values using gemetric mean as ref
01000     // to preserve force_k if provided as single parameter
01001     // (allow changing both via force_k)
01002     lower_wall_k /= force_k;
01003     upper_wall_k /= force_k;
01004   } else {
01005     // If only one wall is defined, need to rescale as well
01006     if (lower_walls.size() > 0) {
01007       force_k = lower_wall_k;
01008       lower_wall_k = 1.0;
01009     }
01010     if (upper_walls.size() > 0) {
01011       force_k = upper_wall_k;
01012       upper_wall_k = 1.0;
01013     }
01014   }
01015 
01016   // Initialize starting value of the force constant (in case it's changing)
01017   starting_force_k = (b_decoupling ? 0.0 : force_k);
01018 
01019   if (lower_walls.size() > 0) {
01020     for (i = 0; i < num_variables(); i++) {
01021       cvm::real const w = variables(i)->width;
01022       cvm::log("The lower wall force constant for colvar \""+
01023                variables(i)->name+"\" will be rescaled to "+
01024                cvm::to_str(lower_wall_k * force_k / (w*w))+
01025                " according to the specified width ("+cvm::to_str(w)+").\n");
01026     }
01027   }
01028 
01029   if (upper_walls.size() > 0) {
01030     for (i = 0; i < num_variables(); i++) {
01031       cvm::real const w = variables(i)->width;
01032       cvm::log("The upper wall force constant for colvar \""+
01033                variables(i)->name+"\" will be rescaled to "+
01034                cvm::to_str(upper_wall_k * force_k / (w*w))+
01035                " according to the specified width ("+cvm::to_str(w)+").\n");
01036     }
01037   }
01038 
01039   return COLVARS_OK;
01040 }
01041 
01042 
01043 int colvarbias_restraint_harmonic_walls::update()
01044 {
01045   int error_code = COLVARS_OK;
01046 
01047   error_code |= colvarbias_ti::update();
01048 
01049   error_code |= colvarbias_restraint_k_moving::update();
01050 
01051   error_code |= colvarbias_restraint::update();
01052 
01053   error_code |= colvarbias_restraint_k_moving::update_acc_work();
01054 
01055   return error_code;
01056 }
01057 
01058 
01059 cvm::real colvarbias_restraint_harmonic_walls::colvar_distance(size_t i) const
01060 {
01061   colvar *cv = variables(i);
01062 
01063   colvarvalue const &cvv = is_enabled(f_cvb_bypass_ext_lagrangian) ?
01064     variables(i)->actual_value() :
01065     variables(i)->value();
01066 
01067   // For a periodic colvar, both walls may be applicable at the same time
01068   // in which case we pick the closer one
01069 
01070   if (cv->is_enabled(f_cv_periodic)) {
01071     cvm::real const lower_wall_dist2 = cv->dist2(cvv, lower_walls[i]);
01072     cvm::real const upper_wall_dist2 = cv->dist2(cvv, upper_walls[i]);
01073     if (lower_wall_dist2 < upper_wall_dist2) {
01074       cvm::real const grad = cv->dist2_lgrad(cvv, lower_walls[i]);
01075       if (grad < 0.0) { return 0.5 * grad; }
01076     } else {
01077       cvm::real const grad = cv->dist2_lgrad(cvv, upper_walls[i]);
01078       if (grad > 0.0) { return 0.5 * grad; }
01079     }
01080     return 0.0;
01081   }
01082 
01083   if (lower_walls.size() > 0) {
01084     cvm::real const grad = cv->dist2_lgrad(cvv, lower_walls[i]);
01085     if (grad < 0.0) { return 0.5 * grad; }
01086   }
01087   if (upper_walls.size() > 0) {
01088     cvm::real const grad = cv->dist2_lgrad(cvv, upper_walls[i]);
01089     if (grad > 0.0) { return 0.5 * grad; }
01090   }
01091   return 0.0;
01092 }
01093 
01094 
01095 cvm::real colvarbias_restraint_harmonic_walls::restraint_potential(size_t i) const
01096 {
01097   cvm::real const dist = colvar_distance(i);
01098   cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
01099   return 0.5 * force_k * scale / (variables(i)->width * variables(i)->width) *
01100     dist * dist;
01101 }
01102 
01103 
01104 colvarvalue const colvarbias_restraint_harmonic_walls::restraint_force(size_t i) const
01105 {
01106   cvm::real const dist = colvar_distance(i);
01107   cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
01108   return - force_k * scale / (variables(i)->width * variables(i)->width) * dist;
01109 }
01110 
01111 
01112 cvm::real colvarbias_restraint_harmonic_walls::d_restraint_potential_dk(size_t i) const
01113 {
01114   cvm::real const dist = colvar_distance(i);
01115   cvm::real const scale = dist > 0.0 ? upper_wall_k : lower_wall_k;
01116   return 0.5 * scale / (variables(i)->width * variables(i)->width) *
01117     dist * dist;
01118 }
01119 
01120 
01121 std::string const colvarbias_restraint_harmonic_walls::get_state_params() const
01122 {
01123   return colvarbias_restraint::get_state_params() +
01124     colvarbias_restraint_moving::get_state_params() +
01125     colvarbias_restraint_k_moving::get_state_params();
01126 }
01127 
01128 
01129 int colvarbias_restraint_harmonic_walls::set_state_params(std::string const &conf)
01130 {
01131   int error_code = COLVARS_OK;
01132   error_code |= colvarbias_restraint::set_state_params(conf);
01133   error_code |= colvarbias_restraint_moving::set_state_params(conf);
01134   error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
01135   return error_code;
01136 }
01137 
01138 
01139 std::ostream & colvarbias_restraint_harmonic_walls::write_state_data(std::ostream &os)
01140 {
01141   return colvarbias_ti::write_state_data(os);
01142 }
01143 
01144 
01145 std::istream & colvarbias_restraint_harmonic_walls::read_state_data(std::istream &is)
01146 {
01147   return colvarbias_ti::read_state_data(is);
01148 }
01149 
01150 
01151 std::ostream & colvarbias_restraint_harmonic_walls::write_traj_label(std::ostream &os)
01152 {
01153   colvarbias_restraint::write_traj_label(os);
01154   colvarbias_restraint_k_moving::write_traj_label(os);
01155   return os;
01156 }
01157 
01158 
01159 std::ostream & colvarbias_restraint_harmonic_walls::write_traj(std::ostream &os)
01160 {
01161   colvarbias_restraint::write_traj(os);
01162   colvarbias_restraint_k_moving::write_traj(os);
01163   return os;
01164 }
01165 
01166 
01167 
01168 colvarbias_restraint_linear::colvarbias_restraint_linear(char const *key)
01169   : colvarbias(key),
01170     colvarbias_ti(key),
01171     colvarbias_restraint(key),
01172     colvarbias_restraint_centers(key),
01173     colvarbias_restraint_moving(key),
01174     colvarbias_restraint_k(key),
01175     colvarbias_restraint_centers_moving(key),
01176     colvarbias_restraint_k_moving(key)
01177 {
01178   check_positive_k = false;
01179 }
01180 
01181 
01182 int colvarbias_restraint_linear::init(std::string const &conf)
01183 {
01184   colvarbias_restraint::init(conf);
01185   colvarbias_restraint_moving::init(conf);
01186   colvarbias_restraint_centers_moving::init(conf);
01187   colvarbias_restraint_k_moving::init(conf);
01188 
01189   cvm::main()->cite_feature("harmonicWalls colvar bias implementation");
01190 
01191   for (size_t i = 0; i < num_variables(); i++) {
01192     if (variables(i)->is_enabled(f_cv_periodic)) {
01193       cvm::error("Error: linear biases cannot be applied to periodic variables.\n",
01194                  COLVARS_INPUT_ERROR);
01195       return COLVARS_INPUT_ERROR;
01196     }
01197     cvm::real const w = variables(i)->width;
01198     cvm::log("The force constant for colvar \""+variables(i)->name+
01199              "\" will be rescaled to "+
01200              cvm::to_str(force_k / w)+
01201              " according to the specified width ("+cvm::to_str(w)+").\n");
01202   }
01203 
01204   return COLVARS_OK;
01205 }
01206 
01207 
01208 int colvarbias_restraint_linear::update()
01209 {
01210   int error_code = COLVARS_OK;
01211 
01212   // update the TI estimator (if defined)
01213   error_code |= colvarbias_ti::update();
01214 
01215   // update parameters (centers or force constant)
01216   error_code |= colvarbias_restraint_centers_moving::update();
01217   error_code |= colvarbias_restraint_k_moving::update();
01218 
01219   // update restraint energy and forces
01220   error_code |= colvarbias_restraint::update();
01221 
01222   // update accumulated work using the current forces
01223   error_code |= colvarbias_restraint_centers_moving::update_acc_work();
01224   error_code |= colvarbias_restraint_k_moving::update_acc_work();
01225 
01226   return error_code;
01227 }
01228 
01229 
01230 int colvarbias_restraint_linear::change_configuration(std::string const &conf)
01231 {
01232   // Only makes sense to change the force constant
01233   return colvarbias_restraint_k::change_configuration(conf);
01234 }
01235 
01236 
01237 cvm::real colvarbias_restraint_linear::energy_difference(std::string const &conf)
01238 {
01239   cvm::real const old_bias_energy = bias_energy;
01240   cvm::real const old_force_k = force_k;
01241 
01242   change_configuration(conf);
01243   update();
01244 
01245   cvm::real const result = (bias_energy - old_bias_energy);
01246 
01247   bias_energy = old_bias_energy;
01248   force_k = old_force_k;
01249 
01250   return result;
01251 }
01252 
01253 
01254 cvm::real colvarbias_restraint_linear::restraint_potential(size_t i) const
01255 {
01256   return force_k / variables(i)->width * (variables(i)->value() -
01257                                           colvar_centers[i]).sum();
01258 }
01259 
01260 
01261 colvarvalue const colvarbias_restraint_linear::restraint_force(size_t i) const
01262 {
01263   colvarvalue dummy(variables(i)->value());
01264   dummy.set_ones();
01265   return -1.0 * force_k / variables(i)->width * dummy;
01266 }
01267 
01268 
01269 cvm::real colvarbias_restraint_linear::d_restraint_potential_dk(size_t i) const
01270 {
01271   return 1.0 / variables(i)->width * (variables(i)->value() -
01272                                       colvar_centers[i]).sum();
01273 }
01274 
01275 
01276 std::string const colvarbias_restraint_linear::get_state_params() const
01277 {
01278   return colvarbias_restraint::get_state_params() +
01279     colvarbias_restraint_moving::get_state_params() +
01280     colvarbias_restraint_centers_moving::get_state_params() +
01281     colvarbias_restraint_k_moving::get_state_params();
01282 }
01283 
01284 
01285 int colvarbias_restraint_linear::set_state_params(std::string const &conf)
01286 {
01287   int error_code = COLVARS_OK;
01288   error_code |= colvarbias_restraint::set_state_params(conf);
01289   error_code |= colvarbias_restraint_moving::set_state_params(conf);
01290   error_code |= colvarbias_restraint_centers_moving::set_state_params(conf);
01291   error_code |= colvarbias_restraint_k_moving::set_state_params(conf);
01292   return error_code;
01293 }
01294 
01295 
01296 std::ostream & colvarbias_restraint_linear::write_state_data(std::ostream &os)
01297 {
01298   return colvarbias_ti::write_state_data(os);
01299 }
01300 
01301 
01302 std::istream & colvarbias_restraint_linear::read_state_data(std::istream &is)
01303 {
01304   return colvarbias_ti::read_state_data(is);
01305 }
01306 
01307 
01308 std::ostream & colvarbias_restraint_linear::write_traj_label(std::ostream &os)
01309 {
01310   colvarbias_restraint::write_traj_label(os);
01311   colvarbias_restraint_centers_moving::write_traj_label(os);
01312   colvarbias_restraint_k_moving::write_traj_label(os);
01313   return os;
01314 }
01315 
01316 
01317 std::ostream & colvarbias_restraint_linear::write_traj(std::ostream &os)
01318 {
01319   colvarbias_restraint::write_traj(os);
01320   colvarbias_restraint_centers_moving::write_traj(os);
01321   colvarbias_restraint_k_moving::write_traj(os);
01322   return os;
01323 }
01324 
01325 
01326 
01327 colvarbias_restraint_histogram::colvarbias_restraint_histogram(char const *key)
01328   : colvarbias(key)
01329 {
01330   lower_boundary = 0.0;
01331   upper_boundary = 0.0;
01332   width = 0.0;
01333   gaussian_width = 0.0;
01334 }
01335 
01336 
01337 int colvarbias_restraint_histogram::init(std::string const &conf)
01338 {
01339   int error_code = COLVARS_OK;
01340 
01341   colvarbias::init(conf);
01342   enable(f_cvb_apply_force);
01343 
01344   cvm::main()->cite_feature("histogramRestraint colvar bias implementation");
01345 
01346   get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary);
01347   get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary);
01348   get_keyval(conf, "width", width, width);
01349 
01350   if (width <= 0.0) {
01351     error_code |= cvm::error("Error: \"width\" must be positive.\n",
01352                              COLVARS_INPUT_ERROR);
01353   }
01354 
01355   get_keyval(conf, "gaussianWidth", gaussian_width, 2.0 * width, colvarparse::parse_silent);
01356   get_keyval(conf, "gaussianSigma", gaussian_width, 2.0 * width);
01357 
01358   if (lower_boundary >= upper_boundary) {
01359     error_code |= cvm::error("Error: the upper boundary, "+
01360                              cvm::to_str(upper_boundary)+
01361                              ", is not higher than the lower boundary, "+
01362                              cvm::to_str(lower_boundary)+".\n",
01363                              COLVARS_INPUT_ERROR);
01364   }
01365 
01366   cvm::real const nbins = (upper_boundary - lower_boundary) / width;
01367   int const nbins_round = (int)(nbins);
01368 
01369   if (cvm::fabs(nbins - cvm::real(nbins_round)) > 1.0E-10) {
01370     cvm::log("Warning: grid interval ("+
01371              cvm::to_str(lower_boundary, cvm::cv_width, cvm::cv_prec)+" - "+
01372              cvm::to_str(upper_boundary, cvm::cv_width, cvm::cv_prec)+
01373              ") is not commensurate to its bin width ("+
01374              cvm::to_str(width, cvm::cv_width, cvm::cv_prec)+").\n");
01375   }
01376 
01377   p.resize(nbins_round);
01378   ref_p.resize(nbins_round);
01379   p_diff.resize(nbins_round);
01380 
01381   bool const inline_ref_p =
01382     get_keyval(conf, "refHistogram", ref_p.data_array(), ref_p.data_array());
01383   std::string ref_p_file;
01384   get_keyval(conf, "refHistogramFile", ref_p_file, std::string(""));
01385   if (ref_p_file.size()) {
01386     if (inline_ref_p) {
01387       error_code |= cvm::error("Error: cannot specify both refHistogram and refHistogramFile at the same time.\n",
01388                                COLVARS_INPUT_ERROR);
01389     } else {
01390 
01391       std::istream &is =
01392         cvm::main()->proxy->input_stream(ref_p_file,
01393                                          "reference histogram file");
01394 
01395       std::string data_s = "";
01396       std::string line;
01397       while (getline_nocomments(is, line)) {
01398         data_s.append(line+"\n");
01399       }
01400       if (data_s.size() == 0) {
01401         error_code |= cvm::error("Error: file \""+ref_p_file+
01402                                  "\" empty or unreadable.\n",
01403                                  COLVARS_FILE_ERROR);
01404       }
01405       error_code |= cvm::main()->proxy->close_input_stream(ref_p_file);
01406 
01407       cvm::vector1d<cvm::real> data;
01408       if (data.from_simple_string(data_s) != 0) {
01409         error_code |= cvm::error("Error: could not read histogram from file \""+
01410                                  ref_p_file+"\".\n");
01411       }
01412       if (data.size() == 2*ref_p.size()) {
01413         // file contains both x and p(x)
01414         size_t i;
01415         for (i = 0; i < ref_p.size(); i++) {
01416           ref_p[i] = data[2*i+1];
01417         }
01418       } else if (data.size() == ref_p.size()) {
01419         ref_p = data;
01420       } else {
01421         error_code |= cvm::error("Error: file \""+ref_p_file+
01422                                  "\" contains a histogram of different length.\n",
01423                                  COLVARS_INPUT_ERROR);
01424       }
01425     }
01426   }
01427 
01428   cvm::real const ref_integral = ref_p.sum() * width;
01429   if (cvm::fabs(ref_integral - 1.0) > 1.0e-03) {
01430     cvm::log("Reference distribution not normalized, normalizing to unity.\n");
01431     ref_p /= ref_integral;
01432   }
01433 
01434   get_keyval(conf, "writeHistogram", b_write_histogram, false);
01435   get_keyval(conf, "forceConstant", force_k, 1.0);
01436 
01437   return error_code;
01438 }
01439 
01440 
01441 colvarbias_restraint_histogram::~colvarbias_restraint_histogram()
01442 {
01443   p.clear();
01444   ref_p.clear();
01445   p_diff.clear();
01446 }
01447 
01448 
01449 int colvarbias_restraint_histogram::update()
01450 {
01451   if (cvm::debug())
01452     cvm::log("Updating the histogram restraint bias \""+this->name+"\".\n");
01453 
01454   size_t vector_size = 0;
01455   size_t icv;
01456   for (icv = 0; icv < num_variables(); icv++) {
01457     vector_size += variables(icv)->value().size();
01458   }
01459 
01460   cvm::real const norm = 1.0/(cvm::sqrt(2.0*PI)*gaussian_width*vector_size);
01461 
01462   // calculate the histogram
01463   p.reset();
01464   for (icv = 0; icv < num_variables(); icv++) {
01465     colvarvalue const &cv = variables(icv)->value();
01466     if (cv.type() == colvarvalue::type_scalar) {
01467       cvm::real const cv_value = cv.real_value;
01468       size_t igrid;
01469       for (igrid = 0; igrid < p.size(); igrid++) {
01470         cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
01471         p[igrid] += norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
01472                                     (2.0 * gaussian_width * gaussian_width));
01473       }
01474     } else if (cv.type() == colvarvalue::type_vector) {
01475       size_t idim;
01476       for (idim = 0; idim < cv.vector1d_value.size(); idim++) {
01477         cvm::real const cv_value = cv.vector1d_value[idim];
01478         size_t igrid;
01479         for (igrid = 0; igrid < p.size(); igrid++) {
01480           cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
01481           p[igrid] += norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
01482                                       (2.0 * gaussian_width * gaussian_width));
01483         }
01484       }
01485     } else {
01486       cvm::error("Error: unsupported type for variable "+variables(icv)->name+".\n",
01487                  COLVARS_NOT_IMPLEMENTED);
01488       return COLVARS_NOT_IMPLEMENTED;
01489     }
01490   }
01491 
01492   cvm::real const force_k_cv = force_k * vector_size;
01493 
01494   // calculate the difference between current and reference
01495   p_diff = p - ref_p;
01496   bias_energy = 0.5 * force_k_cv * p_diff * p_diff;
01497 
01498   // calculate the forces
01499   for (icv = 0; icv < num_variables(); icv++) {
01500     colvarvalue const &cv = variables(icv)->value();
01501     colvarvalue &cv_force = colvar_forces[icv];
01502     cv_force.type(cv);
01503     cv_force.reset();
01504 
01505     if (cv.type() == colvarvalue::type_scalar) {
01506       cvm::real const cv_value = cv.real_value;
01507       cvm::real &force = cv_force.real_value;
01508       size_t igrid;
01509       for (igrid = 0; igrid < p.size(); igrid++) {
01510         cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
01511         force += force_k_cv * p_diff[igrid] *
01512           norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
01513                           (2.0 * gaussian_width * gaussian_width)) *
01514           (-1.0 * (x_grid - cv_value) / (gaussian_width * gaussian_width));
01515       }
01516     } else if (cv.type() == colvarvalue::type_vector) {
01517       size_t idim;
01518       for (idim = 0; idim < cv.vector1d_value.size(); idim++) {
01519         cvm::real const cv_value = cv.vector1d_value[idim];
01520         cvm::real &force = cv_force.vector1d_value[idim];
01521         size_t igrid;
01522         for (igrid = 0; igrid < p.size(); igrid++) {
01523           cvm::real const x_grid = (lower_boundary + (igrid+0.5)*width);
01524           force += force_k_cv * p_diff[igrid] *
01525             norm * cvm::exp(-1.0 * (x_grid - cv_value) * (x_grid - cv_value) /
01526                             (2.0 * gaussian_width * gaussian_width)) *
01527             (-1.0 * (x_grid - cv_value) / (gaussian_width * gaussian_width));
01528         }
01529       }
01530     } else {
01531       // TODO
01532     }
01533   }
01534 
01535   return COLVARS_OK;
01536 }
01537 
01538 
01539 int colvarbias_restraint_histogram::write_output_files()
01540 {
01541   if (b_write_histogram) {
01542     colvarproxy *proxy = cvm::main()->proxy;
01543     std::string file_name(cvm::output_prefix()+"."+this->name+".hist.dat");
01544     std::ostream &os = proxy->output_stream(file_name,
01545                                             "histogram output file");
01546     os << "# " << cvm::wrap_string(variables(0)->name, cvm::cv_width)
01547        << "  " << "p(" << cvm::wrap_string(variables(0)->name, cvm::cv_width-3)
01548        << ")\n";
01549 
01550     os.setf(std::ios::fixed, std::ios::floatfield);
01551 
01552     size_t igrid;
01553     for (igrid = 0; igrid < p.size(); igrid++) {
01554       cvm::real const x_grid = (lower_boundary + (igrid+1)*width);
01555       os << "  "
01556          << std::setprecision(cvm::cv_prec)
01557          << std::setw(cvm::cv_width)
01558          << x_grid
01559          << "  "
01560          << std::setprecision(cvm::cv_prec)
01561          << std::setw(cvm::cv_width)
01562          << p[igrid] << "\n";
01563     }
01564     proxy->close_output_stream(file_name);
01565   }
01566   return COLVARS_OK;
01567 }
01568 
01569 
01570 std::ostream & colvarbias_restraint_histogram::write_traj_label(std::ostream &os)
01571 {
01572   os << " ";
01573   if (b_output_energy) {
01574     os << " E_"
01575        << cvm::wrap_string(this->name, cvm::en_width-2);
01576   }
01577   return os;
01578 }
01579 
01580 
01581 std::ostream & colvarbias_restraint_histogram::write_traj(std::ostream &os)
01582 {
01583   os << " ";
01584   if (b_output_energy) {
01585     os << " "
01586        << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width)
01587        << bias_energy;
01588   }
01589   return os;
01590 }

Generated on Fri Apr 19 02:43:59 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002