Commit 11de8daf authored by Giacomo Fiorin's avatar Giacomo Fiorin
Browse files

Update Colvars library to version 2018-11-16

Fixes several issues with running averages and time correlation function
computations.  Details are in:

https://github.com/Colvars/colvars/issues/143
https://github.com/Colvars/colvars/issues/193
https://github.com/Colvars/colvars/pull/194
parent cf79751f
Loading
Loading
Loading
Loading
+335 B (607 KiB)

File changed.

No diff preview for this file type.

+143 −96
Original line number Diff line number Diff line
@@ -21,10 +21,14 @@


colvar::colvar()
  : prev_timestep(-1)
{
  // Initialize static array once and for all
  runave_os = NULL;

  prev_timestep = -1;
  after_restart = false;
  kinetic_energy = 0.0;
  potential_energy = 0.0;

  init_cv_requires();
}

@@ -38,6 +42,7 @@ namespace {
  }
}


int colvar::init(std::string const &conf)
{
  cvm::log("Initializing a new collective variable.\n");
@@ -48,7 +53,7 @@ int colvar::init(std::string const &conf)
  colvarmodule *cv = cvm::main();

  get_keyval(conf, "name", this->name,
             (std::string("colvar")+cvm::to_str(cv->variables()->size()+1)));
             (std::string("colvar")+cvm::to_str(cv->variables()->size())));

  if ((cvm::colvar_by_name(this->name) != NULL) &&
      (cvm::colvar_by_name(this->name) != this)) {
@@ -63,9 +68,6 @@ int colvar::init(std::string const &conf)

  this->description = "colvar " + this->name;

  kinetic_energy = 0.0;
  potential_energy = 0.0;

  error_code |= init_components(conf);
  if (error_code != COLVARS_OK) {
    return cvm::get_error();
@@ -260,7 +262,6 @@ int colvar::init(std::string const &conf)
  f_old.reset();

  x_restart.type(value());
  after_restart = false;

  reset_bias_force();

@@ -282,8 +283,7 @@ int colvar::init(std::string const &conf)
  // Now that the children are defined we can solve dependencies
  enable(f_cv_active);

  if (cvm::b_analysis)
    parse_analysis(conf);
  error_code |= parse_analysis(conf);

  if (cvm::debug())
    cvm::log("Done initializing collective variable \""+this->name+"\".\n");
@@ -881,19 +881,7 @@ int colvar::parse_analysis(std::string const &conf)
      cvm::error("Error: runAveStride must be commensurate with the restart frequency.\n", INPUT_ERROR);
    }

    get_keyval(conf, "runAveOutputFile", runave_outfile,
                std::string(cvm::output_prefix()+"."+
                             this->name+".runave.traj"));

    size_t const this_cv_width = x.output_width(cvm::cv_width);
    cvm::proxy->backup_file(runave_outfile);
    runave_os = cvm::proxy->output_stream(runave_outfile);
    *runave_os << "# " << cvm::wrap_string("step", cvm::it_width-2)
               << "  "
               << cvm::wrap_string("running average", this_cv_width)
               << " "
               << cvm::wrap_string("running stddev", this_cv_width)
               << "\n";
    get_keyval(conf, "runAveOutputFile", runave_outfile, runave_outfile);
  }

  acf_length = 0;
@@ -902,7 +890,6 @@ int colvar::parse_analysis(std::string const &conf)

    enable(f_cv_corrfunc);

    std::string acf_colvar_name;
    get_keyval(conf, "corrFuncWithColvar", acf_colvar_name, this->name);
    if (acf_colvar_name == this->name) {
      cvm::log("Calculating auto-correlation function.\n");
@@ -918,8 +905,12 @@ int colvar::parse_analysis(std::string const &conf)
    } else if (acf_type_str == to_lower_cppstr(std::string("velocity"))) {
      acf_type = acf_vel;
      enable(f_cv_fdiff_velocity);
      if (acf_colvar_name.size())
        (cvm::colvar_by_name(acf_colvar_name))->enable(f_cv_fdiff_velocity);
      colvar *cv2 = cvm::colvar_by_name(acf_colvar_name);
      if (cv2 == NULL) {
        return cvm::error("Error: collective variable \""+acf_colvar_name+
                          "\" is not defined at this time.\n", INPUT_ERROR);
      }
      cv2->enable(f_cv_fdiff_velocity);
    } else if (acf_type_str == to_lower_cppstr(std::string("coordinate_p2"))) {
      acf_type = acf_p2coor;
    } else {
@@ -937,9 +928,7 @@ int colvar::parse_analysis(std::string const &conf)
    }

    get_keyval(conf, "corrFuncNormalize", acf_normalize, true);
    get_keyval(conf, "corrFuncOutputFile", acf_outfile,
                std::string(cvm::output_prefix()+"."+this->name+
                             ".corrfunc.dat"));
    get_keyval(conf, "corrFuncOutputFile", acf_outfile, acf_outfile);
  }
  return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}
@@ -1389,9 +1378,9 @@ int colvar::calc_colvar_properties()
{
  if (is_enabled(f_cv_fdiff_velocity)) {
    // calculate the velocity by finite differences
    if (cvm::step_relative() == 0)
    if (cvm::step_relative() == 0) {
      x_old = x;
    else {
    } else {
      v_fdiff = fdiff_velocity(x_old, x);
      v_reported = v_fdiff;
    }
@@ -1486,7 +1475,6 @@ cvm::real colvar::update_forces_energy()
        return 0.;
      }
    }
    prev_timestep = cvm::step_relative();

    // Integrate with slow timestep (if time_step_factor != 1)
    cvm::real dt = cvm::dt() * cvm::real(time_step_factor);
@@ -1547,8 +1535,18 @@ cvm::real colvar::update_forces_energy()
  // bypass the extended Lagrangian mass)
  f += fb_actual;

  if (cvm::debug())
    cvm::log("Done updating colvar \""+this->name+"\".\n");
  return (potential_energy + kinetic_energy);
}


int colvar::end_of_step()
{
  if (cvm::debug())
    cvm::log("End of step for colvar \""+this->name+"\".\n");

  if (is_enabled(f_cv_fdiff_velocity)) {
    // set it for the next step
    x_old = x;
  }

@@ -1556,9 +1554,9 @@ cvm::real colvar::update_forces_energy()
    f_old = f;
  }

  if (cvm::debug())
    cvm::log("Done updating colvar \""+this->name+"\".\n");
  return (potential_energy + kinetic_energy);
  prev_timestep = cvm::step_relative();

  return COLVARS_OK;
}


@@ -1966,6 +1964,10 @@ std::ostream & colvar::write_restart(std::ostream &os) {

  os << "}\n\n";

  if (runave_os) {
    cvm::main()->proxy->flush_output_stream(runave_os);
  }

  return os;
}

@@ -2075,41 +2077,46 @@ std::ostream & colvar::write_traj(std::ostream &os)
  return os;
}


int colvar::write_output_files()
{
  if (cvm::b_analysis) {
  int error_code = COLVARS_OK;

  if (is_enabled(f_cv_corrfunc)) {
    if (acf.size()) {
      cvm::log("Writing acf to file \""+acf_outfile+"\".\n");

      if (acf_outfile.size() == 0) {
        acf_outfile = std::string(cvm::output_prefix()+"."+this->name+
                                  ".corrfunc.dat");
      }
      cvm::log("Writing correlation function to file \""+acf_outfile+"\".\n");
      cvm::backup_file(acf_outfile.c_str());
      std::ostream *acf_os = cvm::proxy->output_stream(acf_outfile);
      if (!acf_os) return cvm::get_error();
      write_acf(*acf_os);
      error_code |= write_acf(*acf_os);
      cvm::proxy->close_output_stream(acf_outfile);
    }

    if (runave_os) {
      cvm::proxy->close_output_stream(runave_outfile);
      runave_os = NULL;
    }
  }
  return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);

  return error_code;
}



// ******************** ANALYSIS FUNCTIONS ********************

void colvar::analyze()
int colvar::analyze()
{
  int error_code = COLVARS_OK;

  if (is_enabled(f_cv_runave)) {
    calc_runave();
    error_code |= calc_runave();
  }

  if (is_enabled(f_cv_corrfunc)) {
    calc_acf();
    error_code |= calc_acf();
  }

  return error_code;
}


@@ -2122,6 +2129,7 @@ inline void history_add_value(size_t const &history_length,
    history.pop_back();
}


inline void history_incr(std::list< std::list<colvarvalue> >           &history,
                         std::list< std::list<colvarvalue> >::iterator &history_p)
{
@@ -2138,13 +2146,16 @@ int colvar::calc_acf()
  // representation but separated by acf_stride in the time series;
  // the pointer to each vector is changed at every step

  colvar const *cfcv = cvm::colvar_by_name(acf_colvar_name);
  if (cfcv == NULL) {
    return cvm::error("Error: collective variable \""+acf_colvar_name+
                      "\" is not defined at this time.\n", INPUT_ERROR);
  }

  if (acf_x_history.empty() && acf_v_history.empty()) {

    // first-step operations

    colvar *cfcv = (acf_colvar_name.size() ?
                    cvm::colvar_by_name(acf_colvar_name) :
                    this);
    if (colvarvalue::check_types(cfcv->value(), value())) {
      cvm::error("Error: correlation function between \""+cfcv->name+
                 "\" and \""+this->name+"\" cannot be calculated, "
@@ -2153,7 +2164,8 @@ int colvar::calc_acf()
    }
    acf_nframes = 0;

    cvm::log("Colvar \""+this->name+"\": initializing ACF calculation.\n");
    cvm::log("Colvar \""+this->name+"\": initializing correlation function "
             "calculation.\n");

    if (acf.size() < acf_length+1)
      acf.resize(acf_length+1, 0.0);
@@ -2182,41 +2194,31 @@ int colvar::calc_acf()
      break;
    }

  } else {

    colvar *cfcv = (acf_colvar_name.size() ?
                    cvm::colvar_by_name(acf_colvar_name) :
                    this);
  } else if (cvm::step_relative() > prev_timestep) {

    switch (acf_type) {

    case acf_vel:

      if (is_enabled(f_cv_fdiff_velocity)) {
        // calc() should do this already, but this only happens in a
        // simulation; better do it again in case a trajectory is
        // being read
        v_reported = v_fdiff = fdiff_velocity(x_old, cfcv->value());
      }

      calc_vel_acf((*acf_v_history_p), cfcv->velocity());
      // store this value in the history
      history_add_value(acf_length+acf_offset, *acf_v_history_p, cfcv->velocity());
      // if stride is larger than one, cycle among different histories
      history_add_value(acf_length+acf_offset, *acf_v_history_p,
                        cfcv->velocity());
      history_incr(acf_v_history, acf_v_history_p);
      break;

    case acf_coor:

      calc_coor_acf((*acf_x_history_p), cfcv->value());
      history_add_value(acf_length+acf_offset, *acf_x_history_p, cfcv->value());
      history_add_value(acf_length+acf_offset, *acf_x_history_p,
                        cfcv->value());
      history_incr(acf_x_history, acf_x_history_p);
      break;

    case acf_p2coor:

      calc_p2coor_acf((*acf_x_history_p), cfcv->value());
      history_add_value(acf_length+acf_offset, *acf_x_history_p, cfcv->value());
      history_add_value(acf_length+acf_offset, *acf_x_history_p,
                        cfcv->value());
      history_incr(acf_x_history, acf_x_history_p);
      break;

@@ -2225,18 +2227,14 @@ int colvar::calc_acf()
    }
  }

  if (is_enabled(f_cv_fdiff_velocity)) {
    // set it for the next step
    x_old = x;
  }
  return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
  return COLVARS_OK;
}


int colvar::calc_vel_acf(std::list<colvarvalue> &v_list,
void colvar::calc_vel_acf(std::list<colvarvalue> &v_list,
                          colvarvalue const      &v)
{
  // loop over stored velocities and add to the ACF, but only the
  // loop over stored velocities and add to the ACF, but only if the
  // length is sufficient to hold an entire row of ACF values
  if (v_list.size() >= acf_length+acf_offset) {
    std::list<colvarvalue>::iterator  vs_i = v_list.begin();
@@ -2255,7 +2253,6 @@ int colvar::calc_vel_acf(std::list<colvarvalue> &v_list,

    acf_nframes++;
  }
  return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
}


@@ -2301,20 +2298,46 @@ void colvar::calc_p2coor_acf(std::list<colvarvalue> &x_list,
}


void colvar::write_acf(std::ostream &os)
int colvar::write_acf(std::ostream &os)
{
  if (!acf_nframes)
    cvm::log("Warning: ACF was not calculated (insufficient frames).\n");
  if (!acf_nframes) {
    return COLVARS_OK;
  }

  os.setf(std::ios::scientific, std::ios::floatfield);
  os << "# Autocorrelation function for collective variable \""
  os << "# ";
  switch (acf_type) {
  case acf_vel:
    os << "Velocity";
    break;
  case acf_coor:
    os << "Coordinate";
    break;
  case acf_p2coor:
    os << "Coordinate (2nd Legendre poly)";
    break;
  }

  if (acf_colvar_name == name) {
    os << " autocorrelation function for variable \""
       << this->name << "\"\n";
  // one frame is used for normalization, the statistical sample is
  // hence decreased
  os << "# nframes = " << (acf_normalize ?
                           acf_nframes - 1 :
                           acf_nframes) << "\n";
  } else {
    os << " correlation function between variables \"" //
       << this->name << "\" and \"" << acf_colvar_name << "\"\n";
  }

  os << "# Number of samples = ";
  if (acf_normalize) {
    os << (acf_nframes-1) << " (one DoF is used for normalization)\n";
  } else {
    os << acf_nframes << "\n";
  }

  os << "# " << cvm::wrap_string("step", cvm::it_width-2) << " "
     << cvm::wrap_string("corrfunc(step)", cvm::cv_width) << "\n";

  cvm::real const acf_norm = acf.front() / cvm::real(acf_nframes);

  std::vector<cvm::real>::iterator acf_i;
  size_t it = acf_offset;
  for (acf_i = acf.begin(); acf_i != acf.end(); ++acf_i) {
@@ -2325,11 +2348,15 @@ void colvar::write_acf(std::ostream &os)
            (*acf_i)/(acf_norm * cvm::real(acf_nframes)) :
            (*acf_i)/(cvm::real(acf_nframes)) ) << "\n";
  }

  return os.good() ? COLVARS_OK : FILE_ERROR;
}


void colvar::calc_runave()
int colvar::calc_runave()
{
  int error_code = COLVARS_OK;

  if (x_history.empty()) {

    runave.type(value().type());
@@ -2348,10 +2375,29 @@ void colvar::calc_runave()

  } else {

    if ( (cvm::step_relative() % runave_stride) == 0) {
    if ( (cvm::step_relative() % runave_stride) == 0 &&
         (cvm::step_relative() > prev_timestep) ) {

      if ((*x_history_p).size() >= runave_length-1) {

        if (runave_os == NULL) {
          if (runave_outfile.size() == 0) {
            runave_outfile = std::string(cvm::output_prefix()+"."+
                                         this->name+".runave.traj");
          }

          size_t const this_cv_width = x.output_width(cvm::cv_width);
          cvm::proxy->backup_file(runave_outfile);
          runave_os = cvm::proxy->output_stream(runave_outfile);
          runave_os->setf(std::ios::scientific, std::ios::floatfield);
          *runave_os << "# " << cvm::wrap_string("step", cvm::it_width-2)
                     << "   "
                     << cvm::wrap_string("running average", this_cv_width)
                     << " "
                     << cvm::wrap_string("running stddev", this_cv_width)
                     << "\n";
        }

        runave = x;
        std::list<colvarvalue>::iterator xs_i;
        for (xs_i = (*x_history_p).begin();
@@ -2381,6 +2427,7 @@ void colvar::calc_runave()
    }
  }

  return error_code;
}

// Static members
+11 −7
Original line number Diff line number Diff line
@@ -291,6 +291,9 @@ public:
  /// \brief Calculate the colvar's value and related quantities
  int calc();

  /// Carry out operations needed before next step is run
  int end_of_step();

  /// \brief Calculate a subset of the colvar components (CVCs) currently active
  /// (default: all active CVCs)
  /// Note: both arguments refer to the sect of *active* CVCs, not all CVCs
@@ -410,8 +413,9 @@ public:

  /// Read the analysis tasks
  int parse_analysis(std::string const &conf);

  /// Perform analysis tasks
  void analyze();
  int analyze();


  /// Read the value from a collective variable trajectory file
@@ -489,7 +493,7 @@ protected:
  acf_type_e             acf_type;

  /// \brief Velocity ACF, scalar product between v(0) and v(t)
  int calc_vel_acf(std::list<colvarvalue> &v_history,
  void calc_vel_acf(std::list<colvarvalue> &v_history,
                    colvarvalue const      &v);

  /// \brief Coordinate ACF, scalar product between x(0) and x(t)
@@ -505,7 +509,7 @@ protected:
  /// Calculate the auto-correlation function (ACF)
  int calc_acf();
  /// Save the ACF to a file
  void write_acf(std::ostream &os);
  int write_acf(std::ostream &os);

  /// Length of running average series
  size_t         runave_length;
@@ -521,7 +525,7 @@ protected:
  cvm::real      runave_variance;

  /// Calculate the running average and its standard deviation
  void calc_runave();
  int calc_runave();

  /// If extended Lagrangian active: colvar energies (kinetic and harmonic potential)
  cvm::real kinetic_energy;
+6 −0
Original line number Diff line number Diff line
@@ -236,6 +236,12 @@ void colvarbias::communicate_forces()
}


int colvarbias::end_of_step()
{
  return COLVARS_OK;
}


int colvarbias::change_configuration(std::string const &conf)
{
  cvm::error("Error: change_configuration() not implemented.\n",
+3 −0
Original line number Diff line number Diff line
@@ -66,6 +66,9 @@ public:
  /// Send forces to the collective variables
  virtual void communicate_forces();

  /// Carry out operations needed before next step is run
  virtual int end_of_step();

  /// Load new configuration - force constant and/or centers only
  virtual int change_configuration(std::string const &conf);

Loading