Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

colvarbias_abf.C

Go to the documentation of this file.
00001 /********************************************************************************
00002  * Implementation of the ABF and histogram biases                               *
00003  ********************************************************************************/
00004 
00005 #include "colvarmodule.h"
00006 #include "colvar.h"
00007 #include "colvarbias_abf.h"
00008 
00009 
00011 
00012 colvarbias_abf::colvarbias_abf (std::string const &conf, char const *key)
00013   : colvarbias (conf, key),
00014     gradients (NULL),
00015     samples (NULL)
00016 {
00017   // ************* parsing general ABF options ***********************
00018 
00019   get_keyval (conf, "applybias",  apply_bias, true);
00020   if (!apply_bias) cvm::log ("WARNING: ABF biases will *not* be applied!\n");
00021 
00022   get_keyval (conf, "hidejacobian", hide_Jacobian, false);
00023   if (hide_Jacobian) {
00024     cvm::log ("Jacobian (geometric) forces will be handled internally.\n");
00025   } else {
00026     cvm::log ("Jacobian (geometric) forces will be included in reported free energy gradients.\n");
00027   }
00028 
00029   get_keyval (conf, "fullsamples", full_samples, 200);
00030   if ( full_samples <= 1 ) full_samples = 1; 
00031   min_samples = full_samples / 2;
00032   // full_samples - min_samples >= 1 is guaranteed
00033 
00034   get_keyval (conf, "inputprefix",  input_prefix, std::vector<std::string> ());
00035   get_keyval (conf, "outputfreq", output_freq, cvm::restart_out_freq);
00036 
00037   // ************* checking the associated colvars *******************
00038 
00039   if (colvars.size() == 0) {
00040     cvm::fatal_error ("Error: no collective variables specified for the ABF bias.\n");
00041   }
00042 
00043   for (size_t i = 0; i < colvars.size(); i++) {
00044 
00045     if (colvars[i]->type() != colvarvalue::type_scalar) {
00046       cvm::fatal_error ("Error: ABF bias can only use scalar-type variables.\n");
00047     }
00048 
00049     // Request calculation of system force (which also checks for availability)
00050     colvars[i]->enable (colvar::task_system_force);
00051 
00052     // request computation of Jacobian force
00053     colvars[i]->enable (colvar::task_Jacobian_force);
00054 
00055     // request Jacobian force as part as system force
00056     // except if the user explicitly requires the "silent" Jacobian
00057     // correction AND the colvar has a single component
00058     if (hide_Jacobian) {
00059       if (colvars[i]->n_components() > 1) {
00060         cvm::log ("WARNING: colvar \"" + colvars[i]->name
00061         + "\" has multiple components; reporting its Jacobian forces\n");
00062         colvars[i]->enable (colvar::task_report_Jacobian_force);
00063       }
00064     } else {
00065       colvars[i]->enable (colvar::task_report_Jacobian_force);
00066     }
00067 
00068     // Here we could check for orthogonality of the Cartesian coordinates
00069     // and make it just a warning if some parameter is set? 
00070   }
00071 
00072   bin.assign (colvars.size(), 0);
00073   prev_bin.assign (colvars.size(), 0);
00074   prev_force = new cvm::real [colvars.size()];
00075 
00076   // Construct empty grids based on the colvars
00077   samples   = new colvar_grid_count    (colvars);
00078   gradients = new colvar_grid_gradient (colvars);
00079   gradients->samples = samples;
00080   samples->has_parent_data = true;
00081 
00082   // If custom grids are provided, read them
00083   if ( input_prefix.size() > 0 ) {
00084     read_gradients_samples ();
00085   }
00086   
00087   cvm::log ("Finished ABF setup.\n");
00088 }
00089 
00091 colvarbias_abf::~colvarbias_abf()
00092 {
00093   if (gradients_os.good())      gradients_os.close();
00094   if (samples_os.good())        samples_os.close();
00095 
00096   if (samples) {
00097     delete samples;
00098     samples = NULL;
00099   }
00100 
00101   if (gradients) {
00102     delete gradients;
00103     gradients = NULL;
00104   }
00105 
00106   delete [] prev_force;
00107 }
00108 
00109 
00112 
00113 void colvarbias_abf::update()
00114 {
00115   if (cvm::debug()) cvm::log ("Updating ABF bias " + this->name);
00116 
00117   if (cvm::step_relative() == 0) {
00118         
00119     // At first timestep, do only:
00120     // initialization stuff (file operations relying on n_abf_biases
00121     // compute current value of colvars
00122 
00123     if ( cvm::n_abf_biases == 1 && cvm::n_meta_biases == 0 ) {
00124       // This is the only ABF bias
00125       samples_out_name = cvm::output_prefix + ".count";
00126       gradients_out_name = cvm::output_prefix + ".grad";
00127       if ( colvars.size() == 1 ) {
00128         pmf_out_name = cvm::output_prefix + ".pmf";
00129       }
00130     } else {
00131       samples_out_name = cvm::output_prefix + "." + this->name + ".count";
00132       gradients_out_name = cvm::output_prefix + "." + this->name + ".grad";
00133       if ( colvars.size() == 1 ) {
00134         pmf_out_name = cvm::output_prefix + "." + this->name + ".pmf";
00135       }
00136     }
00137 
00138     for (size_t i=0; i<colvars.size(); i++) {
00139       bin[i]   = colvars[i]->current_bin_scalar();
00140     }
00141 
00142   } else {
00143 
00144     for (size_t i=0; i<colvars.size(); i++) {
00145       bin[i]    = colvars[i]->current_bin_scalar();
00146     }
00147 
00148     if ( samples->index_ok (prev_bin) ) {         // Only within bounds of the grid...
00149 
00150       for (size_t i=0; i<colvars.size(); i++) {   // get forces (lagging by 1 timestep) from colvars...
00151         prev_force[i] = colvars[i]->system_force();
00152       }
00153       gradients->acc_force (prev_bin, prev_force);
00154     }
00155   }
00156 
00157   // save bin for next timestep
00158   prev_bin = bin;  
00159 
00160   // Reset biasing forces from previous timestep
00161   for (size_t i=0; i<colvars.size(); i++) {
00162     colvar_forces[i].reset();
00163   }
00164 
00165   // Compute and apply the new bias, if applicable
00166   if ( apply_bias && samples->index_ok (bin) ) {
00167 
00168     size_t  count = samples->value (bin);
00169     cvm::real   fact = 1.0;
00170 
00171     // Factor that ensures smooth introduction of the force
00172     if ( count < full_samples ) {
00173       fact = ( count < min_samples) ? 0.0 : (cvm::real (count - min_samples)) / (cvm::real (full_samples - min_samples));
00174     }
00175         
00176     const cvm::real * grad  = &(gradients->value (bin));
00177 
00178     if ( fact != 0.0 ) {
00179 
00180       if ( (colvars.size() == 1) && colvars[0]->periodic_boundaries() ) {
00181         // Enforce a zero-mean bias on periodic, 1D coordinates
00182         colvar_forces[0].real_value += fact * (grad[0] / cvm::real (count) - gradients->average ());
00183       } else {
00184         for (size_t i=0; i<colvars.size(); i++) {
00185           // subtracting the mean force (opposite of the FE gradient) means adding the gradient
00186           colvar_forces[i].real_value += fact * grad[i] / cvm::real (count);
00187           // without .real_value, the above would do (cheap) runtime type checking
00188         }
00189       }
00190     }
00191   }
00192 
00193   if (output_freq && (cvm::step_relative() % output_freq) == 0) {
00194     if (cvm::debug()) cvm::log ("ABF bias trying to write gradients and samples to disk");
00195     write_gradients_samples ();
00196   }
00197 }
00198 
00199 void colvarbias_abf::write_gradients_samples ()
00200 {
00201   samples_os.open (samples_out_name.c_str());
00202   if (!samples_os.good()) cvm::fatal_error ("Error opening ABF samples file " + samples_out_name + " for writing");
00203   samples->write_multicol (samples_os);
00204   samples_os.close ();
00205 
00206   gradients_os.open (gradients_out_name.c_str());
00207   if (!gradients_os.good())     cvm::fatal_error ("Error opening ABF gradient file " + gradients_out_name + " for writing");
00208   gradients->write_multicol (gradients_os);
00209   gradients_os.close ();
00210 
00211   if ( colvars.size () == 1 ) {
00212     // Do numerical integration and output a PMF
00213     pmf_os.open (pmf_out_name.c_str());
00214     if (!pmf_os.good()) cvm::fatal_error ("Error opening pmf file " + pmf_out_name + " for writing");
00215     gradients->write_1D_integral (pmf_os);
00216     pmf_os.close ();
00217   }
00218   return;
00219 }
00220 
00221 void colvarbias_abf::read_gradients_samples ()
00222 {
00223   std::string samples_in_name, gradients_in_name;
00224 
00225   for ( size_t i = 0; i < input_prefix.size(); i++ ) {
00226     samples_in_name = input_prefix[i] + ".count";
00227     gradients_in_name = input_prefix[i] + ".grad";
00228     // For user-provided files, the per-bias naming scheme may not apply
00229     
00230     std::ifstream is;
00231 
00232     cvm::log ("Reading sample count from " + samples_in_name + " and gradients from " + gradients_in_name);
00233     is.open (samples_in_name.c_str());
00234     if (!is.good()) cvm::fatal_error ("Error opening ABF samples file " + samples_in_name + " for reading");
00235     samples->read_multicol (is, true);
00236     is.close ();
00237     is.clear();
00238 
00239     is.open (gradients_in_name.c_str());
00240     if (!is.good())     cvm::fatal_error ("Error opening ABF gradient file " + gradients_in_name + " for reading");
00241     gradients->read_multicol (is, true);
00242     is.close ();
00243   }
00244   return;
00245 }
00246 
00247 
00248 std::ostream & colvarbias_abf::write_restart (std::ostream& os)
00249 {
00250 
00251   std::ios::fmtflags flags (os.flags ()); 
00252   os.setf(std::ios::fmtflags (0), std::ios::floatfield); // default floating-point format
00253 
00254   os << "abf {\n"
00255      << "  configuration {\n"
00256      << "    name " << this->name << "\n";
00257   os << "  }\n";
00258 
00259   os << "samples\n";
00260   samples->write_raw (os, 8);
00261 
00262   os << "\ngradient\n";
00263   gradients->write_raw (os);
00264 
00265   os << "}\n\n";
00266 
00267   os.flags (flags);
00268   return os;
00269 }
00270 
00271 
00272 std::istream & colvarbias_abf::read_restart (std::istream& is)
00273 {
00274   if ( input_prefix.size() > 0 ) {
00275     cvm::fatal_error ("ERROR: cannot provide both inputPrefix and restart information (colvarsInput)");
00276   }
00277 
00278   size_t const start_pos = is.tellg();
00279 
00280   cvm::log ("Restarting ABF bias \""+
00281             this->name+"\".\n");
00282   std::string key, brace, conf;
00283 
00284   if ( !(is >> key)   || !(key == "abf") ||
00285        !(is >> brace) || !(brace == "{") ||
00286        !(is >> colvarparse::read_block ("configuration", conf)) ) {
00287     cvm::log ("Error: in reading restart configuration for ABF bias \""+
00288               this->name+"\" at position "+
00289               cvm::to_str (is.tellg())+" in stream.\n");
00290     is.clear();
00291     is.seekg (start_pos, std::ios::beg);
00292     is.setstate (std::ios::failbit);
00293     return is;
00294   }
00295 
00296   std::string name = "";
00297   if ( (colvarparse::get_keyval (conf, "name", name, std::string (""), colvarparse::parse_silent)) &&
00298          (name != this->name) )
00299     cvm::fatal_error ("Error: in the restart file, the "
00300                       "\"abf\" block has wrong name (" + name + ")\n");
00301   if ( name == "" ) {
00302     cvm::fatal_error ("Error: \"abf\" block in the restart file has no name.\n");
00303   }
00304   
00305   if ( !(is >> key)   || !(key == "samples")) {
00306     cvm::log ("Error: in reading restart configuration for ABF bias \""+
00307               this->name+"\" at position "+
00308               cvm::to_str (is.tellg())+" in stream.\n");
00309     is.clear();
00310     is.seekg (start_pos, std::ios::beg);
00311     is.setstate (std::ios::failbit);
00312     return is;
00313   }
00314   samples->read_raw (is);
00315 
00316   if ( !(is >> key)   || !(key == "gradient")) {
00317     cvm::log ("Error: in reading restart configuration for ABF bias \""+
00318               this->name+"\" at position "+
00319               cvm::to_str (is.tellg())+" in stream.\n");
00320     is.clear();
00321     is.seekg (start_pos, std::ios::beg);
00322     is.setstate (std::ios::failbit);
00323     return is;
00324   }
00325   gradients->read_raw (is);
00326 
00327   is >> brace;
00328   if (brace != "}") {
00329     cvm::fatal_error ("Error: corrupt restart information for ABF bias \""+
00330                       this->name+"\": no matching brace at position "+
00331                       cvm::to_str (is.tellg())+" in the restart file.\n");
00332     is.setstate (std::ios::failbit);
00333   }
00334   return is;
00335 }
00336 
00337 
00338 
00339 
00341 //
00342 colvarbias_histogram::colvarbias_histogram (std::string const &conf, char const *key)
00343   : colvarbias (conf, key),
00344     grid (NULL)
00345 {
00346   get_keyval (conf, "outputfreq", output_freq, cvm::restart_out_freq);
00347 
00348   if ( output_freq == 0 ) {
00349     cvm::fatal_error ("User required histogram with zero output frequency");
00350   }
00351 
00352   grid   = new colvar_grid_count    (colvars);
00353   bin.assign (colvars.size(), 0);
00354 
00355   out_name = cvm::output_prefix + "." + this->name + ".dat";
00356   cvm::log ("Histogram will be written to file " + out_name); 
00357 
00358   cvm::log ("Finished histogram setup.\n");
00359 }
00360 
00362 colvarbias_histogram::~colvarbias_histogram()
00363 {
00364   if (grid_os.good())   grid_os.close();
00365 
00366   if (grid) {
00367     delete grid;
00368     grid = NULL;
00369   }
00370 }
00371 
00373 void colvarbias_histogram::update()
00374 {
00375   if (cvm::debug()) cvm::log ("Updating Grid bias " + this->name);
00376 
00377   for (size_t i=0; i<colvars.size(); i++) {
00378     bin[i] = colvars[i]->current_bin_scalar();
00379   }
00380 
00381   if ( grid->index_ok (bin) ) {   // Only within bounds of the grid...
00382     grid->incr_count (bin);
00383   }
00384 
00385   if (output_freq && (cvm::step_relative() % output_freq) == 0) {
00386     if (cvm::debug()) cvm::log ("Histogram bias trying to write grid to disk");
00387 
00388     grid_os.open (out_name.c_str());
00389     if (!grid_os.good()) cvm::fatal_error ("Error opening histogram file " + out_name + " for writing");
00390     grid->write_multicol (grid_os);
00391     grid_os.close ();
00392   }
00393 }
00394 
00395 
00396 std::istream & colvarbias_histogram::read_restart (std::istream& is)
00397 {
00398   size_t const start_pos = is.tellg();
00399 
00400   cvm::log ("Restarting collective variable histogram \""+
00401             this->name+"\".\n");
00402   std::string key, brace, conf;
00403 
00404   if ( !(is >> key)   || !(key == "histogram") ||
00405        !(is >> brace) || !(brace == "{") ||
00406        !(is >> colvarparse::read_block ("configuration", conf)) ) {
00407     cvm::log ("Error: in reading restart configuration for histogram \""+
00408               this->name+"\" at position "+
00409               cvm::to_str (is.tellg())+" in stream.\n");
00410     is.clear();
00411     is.seekg (start_pos, std::ios::beg);
00412     is.setstate (std::ios::failbit);
00413     return is;
00414   }
00415 
00416   int id = -1;
00417   std::string name = "";
00418   if ( (colvarparse::get_keyval (conf, "name", name, std::string (""), colvarparse::parse_silent)) &&
00419          (name != this->name) )
00420     cvm::fatal_error ("Error: in the restart file, the "
00421                       "\"histogram\" block has a wrong name: different system?\n");
00422   if ( (id == -1) && (name == "") ) {
00423     cvm::fatal_error ("Error: \"histogram\" block in the restart file "
00424                       "has no name.\n");
00425   }
00426   
00427   if ( !(is >> key)   || !(key == "grid")) {
00428     cvm::log ("Error: in reading restart configuration for histogram \""+
00429               this->name+"\" at position "+
00430               cvm::to_str (is.tellg())+" in stream.\n");
00431     is.clear();
00432     is.seekg (start_pos, std::ios::beg);
00433     is.setstate (std::ios::failbit);
00434     return is;
00435   }
00436   grid->read_raw (is);
00437 
00438   is >> brace;
00439   if (brace != "}") {
00440     cvm::fatal_error ("Error: corrupt restart information for ABF bias \""+
00441                       this->name+"\": no matching brace at position "+
00442                       cvm::to_str (is.tellg())+" in the restart file.\n");
00443     is.setstate (std::ios::failbit);
00444   }
00445   return is;
00446 }
00447 
00448 std::ostream & colvarbias_histogram::write_restart (std::ostream& os)
00449 {
00450   os << "histogram {\n"
00451      << "  configuration {\n"
00452      << "    name " << this->name << "\n";
00453   os << "  }\n";
00454 
00455   os << "grid\n";
00456   grid->write_raw (os, 8);
00457 
00458   os << "}\n\n";
00459 
00460   return os;
00461 }

Generated on Mon Nov 23 04:59:18 2009 for NAMD by  doxygen 1.3.9.1