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

Generated on Fri May 25 04:07:13 2012 for NAMD by  doxygen 1.3.9.1