From 51a148df161cdb42a984d51add3613eb7bd7e96c Mon Sep 17 00:00:00 2001
From: sjplimp <sjplimp@f3b2605a-c512-4ea7-a41b-209d697bcdaa>
Date: Tue, 28 Oct 2014 19:53:17 +0000
Subject: [PATCH] git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@12650
 f3b2605a-c512-4ea7-a41b-209d697bcdaa

---
 lib/colvars/colvar.cpp               | 132 +++++++++-------
 lib/colvars/colvar.h                 |  11 +-
 lib/colvars/colvaratoms.cpp          |  11 ++
 lib/colvars/colvarbias.cpp           |  18 +++
 lib/colvars/colvarbias.h             |   9 ++
 lib/colvars/colvarbias_abf.cpp       | 145 ++++++++++++++++++
 lib/colvars/colvarbias_abf.h         |  23 ++-
 lib/colvars/colvarbias_meta.cpp      |   1 +
 lib/colvars/colvarcomp.cpp           |  13 +-
 lib/colvars/colvarcomp.h             | 116 --------------
 lib/colvars/colvarcomp_distances.cpp |  15 +-
 lib/colvars/colvargrid.h             |  64 ++++++++
 lib/colvars/colvarmodule.cpp         | 218 ++++++++++++++++++++-------
 lib/colvars/colvarmodule.h           |  44 +++++-
 lib/colvars/colvarproxy.h            |  30 +++-
 lib/colvars/colvarscript.cpp         |   5 +-
 lib/colvars/colvartypes.cpp          |  40 ++---
 lib/colvars/colvartypes.h            |  11 +-
 18 files changed, 632 insertions(+), 274 deletions(-)

diff --git a/lib/colvars/colvar.cpp b/lib/colvars/colvar.cpp
index 96231ec89b..aafa60e1fb 100644
--- a/lib/colvars/colvar.cpp
+++ b/lib/colvars/colvar.cpp
@@ -53,11 +53,17 @@ colvar::colvar (std::string const &conf)
       if (cvcp != NULL) {                                               \
         cvcs.push_back (cvcp);                                          \
         cvcp->check_keywords (def_conf, def_config_key);                \
+        if (cvm::get_error()) {                                         \
+          cvm::error("Error: in setting up component \""                \
+                      def_config_key"\".\n");                           \
+          return;                                                       \
+        }                                                               \
         cvm::decrease_depth();                                          \
       } else {                                                          \
-        cvm::error ("Error: in allocating component \""                 \
+        cvm::error("Error: in allocating component \""                  \
                           def_config_key"\".\n",                        \
                           MEMORY_ERROR);                                \
+        return;                                                         \
       }                                                                 \
       if ( (cvcp->period != 0.0) || (cvcp->wrap_center != 0.0) ) {      \
         if ( (cvcp->function_type != std::string ("distance_z")) &&     \
@@ -70,6 +76,7 @@ colvar::colvar (std::string const &conf)
                             "Period: "+cvm::to_str(cvcp->period) +      \
                         " wrapAround: "+cvm::to_str(cvcp->wrap_center), \
                         INPUT_ERROR);                                   \
+          return;                                                       \
         }                                                               \
       }                                                                 \
       if ( ! cvcs.back()->name.size())                                  \
@@ -150,63 +157,64 @@ colvar::colvar (std::string const &conf)
     "", colvarparse::parse_silent)) {
 
     enable(task_scripted);
-    cvm::log("This colvar is a scripted function.");
-
-    std::string type_str;
-    get_keyval (conf, "scriptedFunctionType", type_str, "scalar");
+    cvm::log("This colvar uses scripted function \"" + scripted_function + "\".");
 
-    x.type(colvarvalue::type_notset);
-    for (i = 0; i < colvarvalue::type_all; i++) {
-      if (type_str == colvarvalue::type_keyword[i]) {
-        x.type(colvarvalue::Type(i));
-        break;
-      }
-    }
-    if (x.type() == colvarvalue::type_notset) {
-      cvm::error("Could not parse scripted colvar type.");
-      return;
-    }
-    x_reported.type (x.type());
-    cvm::log(std::string("Expecting colvar value of type ")
-      + colvarvalue::type_desc[x.type()]);
+    // Only accept scalar scripted colvars
+    // might accept other types when the infrastructure is in place
+    // for derivatives of vectors wrt vectors
+    x.type(colvarvalue::type_scalar);
+    x_reported.type(x.type());
 
-    // Build ordered list of component values that will be
-    // passed to the script
+    // Sort array of cvcs based on values of componentExp
+    std::vector<cvc *> temp_vec;
     for (i = 1; i <= cvcs.size(); i++) {
       for (j = 0; j < cvcs.size(); j++) {
         if (cvcs[j]->sup_np == int(i)) {
-          sorted_cvc_values.push_back(cvcs[j]->p_value());
+          temp_vec.push_back(cvcs[j]);
           break;
         }
       }
     }
-    if (sorted_cvc_values.size() != cvcs.size()) {
-      cvm::error("Could not find order numbers for all components"
+    if (temp_vec.size() != cvcs.size()) {
+      cvm::error("Could not find order numbers for all components "
                   "in componentExp values.");
       return;
     }
-  }
+    cvcs = temp_vec;
 
-  // this is set false if any of the components has an exponent
-  // different from 1 in the polynomial
-  b_linear = true;
+    // Build ordered list of component values that will be
+    // passed to the script
+    for (j = 0; j < cvcs.size(); j++) {
+      sorted_cvc_values.push_back(cvcs[j]->p_value());
+    }
+  }
 
-  // these will be set to false if any of the cvcs has them false
-  b_inverse_gradients = true;
-  b_Jacobian_force    = true;
+  if (!tasks[task_scripted]) {
+    // this is set false if any of the components has an exponent
+    // different from 1 in the polynomial
+    b_linear = true;
+    // these will be set to false if any of the cvcs has them false
+    b_inverse_gradients = true;
+    b_Jacobian_force    = true;
+  }
 
+  // Test whether this is a single-component variable
   // Decide whether the colvar is periodic
   // Used to wrap extended DOF if extendedLagrangian is on
-  if (cvcs.size() == 1 && (cvcs[0])->b_periodic && (cvcs[0])->sup_np == 1
-                                                && (cvcs[0])->sup_coeff == 1.0 ) {
-    this->b_periodic = true;
-    this->period = (cvcs[0])->period;
+  if (cvcs.size() == 1  && (cvcs[0])->sup_np == 1
+                        && (cvcs[0])->sup_coeff == 1.0
+                        && !tasks[task_scripted]) {
+
+    b_single_cvc = true;
+    b_periodic = (cvcs[0])->b_periodic;
+    period = (cvcs[0])->period;
     // TODO write explicit wrap() function for colvars to allow for
     // sup_coeff different from 1
     // this->period = (cvcs[0])->period * (cvcs[0])->sup_coeff;
   } else {
-    this->b_periodic = false;
-    this->period = 0.0;
+    b_single_cvc = false;
+    b_periodic = false;
+    period = 0.0;
   }
 
   // check the available features of each cvc
@@ -808,13 +816,14 @@ void colvar::calc()
       // each atom group will take care of its own ref_pos_group, if defined
     }
   }
-  if (tasks[task_output_velocity]) {
-    for (i = 0; i < cvcs.size(); i++) {
-      for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
-        cvcs[i]->atom_groups[ig]->read_velocities();
-      }
-    }
-  }
+////  Don't try to get atom velocities, as no back-end currently implements it
+//   if (tasks[task_output_velocity] && !tasks[task_fdiff_velocity]) {
+//     for (i = 0; i < cvcs.size(); i++) {
+//       for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
+//         cvcs[i]->atom_groups[ig]->read_velocities();
+//       }
+//     }
+//   }
   if (tasks[task_system_force]) {
     for (i = 0; i < cvcs.size(); i++) {
       for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) {
@@ -1153,8 +1162,11 @@ void colvar::communicate_forces()
 
     for (i = 0; i < cvcs.size(); i++) {
       cvm::increase_depth();
-      // Note: we need a dot product here
-      (cvcs[i])->apply_force (f * func_grads[i]);
+      // Force is scalar times colvarvalue (scalar or vector)
+      // Note: this can only handle scalar colvars (scalar values of f)
+      // A non-scalar colvar would need the gradient to be expressed
+      // as an order-2 tensor
+      (cvcs[i])->apply_force (f.real_value * func_grads[i]);
       cvm::decrease_depth();
     }
   } else if (x.type() == colvarvalue::type_scalar) {
@@ -1223,30 +1235,38 @@ bool colvar::periodic_boundaries() const
 cvm::real colvar::dist2 (colvarvalue const &x1,
                          colvarvalue const &x2) const
 {
-  return (cvcs[0])->dist2 (x1, x2);
+  if (b_single_cvc) {
+    return (cvcs[0])->dist2(x1, x2);
+  } else {
+    return x1.dist2(x2);
+  }
 }
 
 colvarvalue colvar::dist2_lgrad (colvarvalue const &x1,
                                  colvarvalue const &x2) const
 {
-  return (cvcs[0])->dist2_lgrad (x1, x2);
+  if (b_single_cvc) {
+    return (cvcs[0])->dist2_lgrad (x1, x2);
+  } else {
+    return x1.dist2_grad(x2);
+  }
 }
 
 colvarvalue colvar::dist2_rgrad (colvarvalue const &x1,
                                  colvarvalue const &x2) const
 {
-  return (cvcs[0])->dist2_rgrad (x1, x2);
-}
-
-cvm::real colvar::compare (colvarvalue const &x1,
-                           colvarvalue const &x2) const
-{
-  return (cvcs[0])->compare (x1, x2);
+  if (b_single_cvc) {
+    return (cvcs[0])->dist2_rgrad (x1, x2);
+  } else {
+    return x2.dist2_grad(x1);
+  }
 }
 
 void colvar::wrap (colvarvalue &x) const
 {
-  (cvcs[0])->wrap (x);
+  if (b_single_cvc) {
+    (cvcs[0])->wrap (x);
+  }
   return;
 }
 
diff --git a/lib/colvars/colvar.h b/lib/colvars/colvar.h
index 896613d7da..3d06cf8df5 100644
--- a/lib/colvars/colvar.h
+++ b/lib/colvars/colvar.h
@@ -83,6 +83,10 @@ public:
   /// combination of \link cvc \endlink elements
   bool b_linear;
 
+  /// \brief True if this \link colvar \endlink is equal to
+  /// its only constituent cvc
+  bool b_single_cvc;
+
   /// \brief True if all \link cvc \endlink objects are capable
   /// of calculating inverse gradients
   bool b_inverse_gradients;
@@ -344,13 +348,6 @@ public:
   colvarvalue dist2_rgrad (colvarvalue const &x1,
                            colvarvalue const &x2) const;
 
-  /// \brief Use the internal metrics (as from \link cvc
-  /// \endlink objects) to compare colvar values
-  ///
-  /// Handles correctly symmetries and periodic boundary conditions
-  cvm::real compare (colvarvalue const &x1,
-                     colvarvalue const &x2) const;
-
   /// \brief Use the internal metrics (as from \link cvc
   /// \endlink objects) to wrap a value into a standard interval
   ///
diff --git a/lib/colvars/colvaratoms.cpp b/lib/colvars/colvaratoms.cpp
index f56871d614..250d23acfa 100644
--- a/lib/colvars/colvaratoms.cpp
+++ b/lib/colvars/colvaratoms.cpp
@@ -138,6 +138,7 @@ int cvm::atom_group::parse (std::string const &conf,
         for (size_t i = 0; i < atom_indexes.size(); i++) {
           this->push_back (cvm::atom (atom_indexes[i]));
         }
+        if (cvm::get_error()) return COLVARS_ERROR;
       } else {
         cvm::error ("Error: no numbers provided for \""
                     "atomNumbers\".\n", INPUT_ERROR);
@@ -166,6 +167,7 @@ int cvm::atom_group::parse (std::string const &conf,
       for (size_t i = 0; i < index_groups_i->size(); i++) {
         this->push_back (cvm::atom ((*index_groups_i)[i]));
       }
+      if (cvm::get_error()) return COLVARS_ERROR;
     }
   }
 
@@ -185,6 +187,7 @@ int cvm::atom_group::parse (std::string const &conf,
           for (int anum = initial; anum <= final; anum++) {
             this->push_back (cvm::atom (anum));
           }
+          if (cvm::get_error()) return COLVARS_ERROR;
           range_conf = "";
           continue;
         }
@@ -235,6 +238,7 @@ int cvm::atom_group::parse (std::string const &conf,
           for (int resid = initial; resid <= final; resid++) {
             this->push_back (cvm::atom (resid, atom_name, psf_segid));
           }
+          if (cvm::get_error()) return COLVARS_ERROR;
           range_conf = "";
         } else {
           cvm::error ("Error: cannot parse definition for \""
@@ -272,6 +276,9 @@ int cvm::atom_group::parse (std::string const &conf,
     }
   }
 
+  // Catch any errors from all the initialization steps above
+  if (cvm::get_error()) return COLVARS_ERROR;
+
   for (std::vector<cvm::atom>::iterator a1 = this->begin();
        a1 != this->end(); ++a1) {
     std::vector<cvm::atom>::iterator a2 = a1;
@@ -433,6 +440,10 @@ int cvm::atom_group::parse (std::string const &conf,
               std::string (key)+"\".\n");
 
   this->check_keywords (group_conf, key);
+  if (cvm::get_error()) {
+    cvm::error("Error setting up atom group \""+std::string (key)+"\".");
+    return COLVARS_ERROR;
+  }
 
   cvm::log ("Atom group \""+std::string (key)+"\" defined, "+
             cvm::to_str (this->size())+" atoms initialized: total mass = "+
diff --git a/lib/colvars/colvarbias.cpp b/lib/colvars/colvarbias.cpp
index d88611b9b9..7c21c551c8 100644
--- a/lib/colvars/colvarbias.cpp
+++ b/lib/colvars/colvarbias.cpp
@@ -124,6 +124,24 @@ cvm::real colvarbias::energy_difference(std::string const &conf)
 }
 
 
+// So far, these are only implemented in colvarsbias_abf
+int colvarbias::bin_num()
+{
+  cvm::error ("Error: bin_num() not implemented.\n");
+  return -1;
+}
+int colvarbias::current_bin()
+{
+  cvm::error ("Error: current_bin() not implemented.\n");
+  return -1;
+}
+int colvarbias::bin_count(int bin_index)
+{
+  cvm::error ("Error: bin_count() not implemented.\n");
+  return -1;
+}
+
+
 std::ostream & colvarbias::write_traj_label (std::ostream &os)
 {
   os << " ";
diff --git a/lib/colvars/colvarbias.h b/lib/colvars/colvarbias.h
index c3624784d1..ad24f40f30 100644
--- a/lib/colvars/colvarbias.h
+++ b/lib/colvars/colvarbias.h
@@ -29,6 +29,15 @@ public:
   /// Calculate change in energy from using alternate configuration
   virtual cvm::real energy_difference(std::string const &conf);
 
+  /// Give the total number of bins for a given bias.
+  virtual int bin_num();
+  /// Calculate the bin index for a given bias.
+  virtual int current_bin();
+  //// Give the count at a given bin index.
+  virtual int bin_count(int bin_index);  
+  //// Share information between replicas, whatever it may be.
+  virtual void replica_share() {};
+
   /// Perform analysis tasks
   virtual inline void analyse() {}
 
diff --git a/lib/colvars/colvarbias_abf.cpp b/lib/colvars/colvarbias_abf.cpp
index cf5825650c..812490013c 100644
--- a/lib/colvars/colvarbias_abf.cpp
+++ b/lib/colvars/colvarbias_abf.cpp
@@ -44,6 +44,18 @@ colvarbias_abf::colvarbias_abf (std::string const &conf, char const *key)
   get_keyval (conf, "historyFreq", history_freq, 0);
   b_history_files = (history_freq > 0);
 
+  // shared ABF
+  get_keyval (conf, "shared", shared_on, false);
+  if (shared_on) {
+    if (!cvm::replica_enabled || cvm::replica_num() <= 1)
+      cvm::error ("Error: shared ABF requires more than one replica.");
+    else
+      cvm::log ("shared ABF will be applied among "+ cvm::to_str(cvm::replica_num()) + " replicas.\n");
+
+    // If shared_freq is not set, we default to output_freq
+    get_keyval (conf, "sharedFreq", shared_freq, output_freq);
+  }
+
   // ************* checking the associated colvars *******************
 
   if (colvars.size() == 0) {
@@ -109,6 +121,15 @@ colvarbias_abf::colvarbias_abf (std::string const &conf, char const *key)
   gradients->samples = samples;
   samples->has_parent_data = true;
 
+  // For shared ABF, we store a second set of grids.
+  // This used to be only if "shared" was defined,
+  // but now we allow calling share externally (e.g. from Tcl).
+  last_samples   = new colvar_grid_count    (colvars);
+  last_gradients = new colvar_grid_gradient (colvars);
+  last_gradients->samples = last_samples;
+  last_samples->has_parent_data = true;
+  shared_last_step = -1;
+
   // If custom grids are provided, read them
   if ( input_prefix.size() > 0 ) {
     read_gradients_samples ();
@@ -130,6 +151,19 @@ colvarbias_abf::~colvarbias_abf()
     gradients = NULL;
   }
 
+  // shared ABF
+  // We used to only do this if "shared" was defined,
+  // but now we can call shared externally
+  if (last_samples) {
+    delete last_samples;
+    last_samples = NULL;
+  }
+
+  if (last_gradients) {
+    delete last_gradients;
+    last_gradients = NULL;
+  }
+
   delete [] force;
 
   if (cvm::n_abf_biases > 0)
@@ -225,13 +259,103 @@ cvm::real colvarbias_abf::update()
     write_gradients_samples (output_prefix);
   }
   if (b_history_files && (cvm::step_absolute() % history_freq) == 0) {
+    cvm::log ("ABFHISTORYFILE "+cvm::to_str(cvm::step_absolute()));
     // append to existing file only if cvm::step_absolute() > 0
     // otherwise, backup and replace
     write_gradients_samples (output_prefix + ".hist", (cvm::step_absolute() > 0));
   }
+
+  if (shared_on && shared_last_step >= 0 && cvm::step_absolute() % shared_freq == 0) {
+    // Share gradients and samples for shared ABF.
+    replica_share();
+  }
+
+  // Prepare for the first sharing.
+  if (shared_last_step < 0) {
+    // Copy the current gradient and count values into last.
+    last_gradients->copy_grid(*gradients);
+    last_samples->copy_grid(*samples);
+    shared_last_step = cvm::step_absolute();
+    cvm::log ("Prepared sample and gradient buffers at step "+cvm::to_str(cvm::step_absolute())+".");
+  }
+
   return 0.0;
 }
 
+void colvarbias_abf::replica_share () {
+  int p;
+
+  if( !cvm::replica_enabled() ) {
+    cvm::error ("Error: shared ABF: No replicas.\n");
+    return;
+  }
+  // We must have stored the last_gradients and last_samples.
+  if (shared_last_step < 0 ) {
+    cvm::error ("Error: shared ABF: Tried to apply shared ABF before any sampling had occurred.\n");
+    return;
+  }
+
+  // Share gradients for shared ABF.
+  cvm::log ("shared ABF: Sharing gradient and samples among replicas at step "+cvm::to_str(cvm::step_absolute()) );
+
+  // Count of data items.
+  size_t data_n = gradients->raw_data_num();
+  size_t samp_start = data_n*sizeof(cvm::real);
+  size_t msg_total = data_n*sizeof(size_t) + samp_start;
+  char* msg_data = new char[msg_total];
+
+  if (cvm::replica_index() == 0) {
+    // Replica 0 collects the delta gradient and count from the others.
+    for (p = 1; p < cvm::replica_num(); p++) {
+      // Receive the deltas.
+      cvm::replica_comm_recv(msg_data, msg_total, p);
+
+      // Map the deltas from the others into the grids.
+      last_gradients->raw_data_in((cvm::real*)(&msg_data[0]));
+      last_samples->raw_data_in((size_t*)(&msg_data[samp_start]));
+
+      // Combine the delta gradient and count of the other replicas
+      // with Replica 0's current state (including its delta).
+      gradients->add_grid( *last_gradients );
+      samples->add_grid( *last_samples );
+    }
+
+    // Now we must send the combined gradient to the other replicas.
+    gradients->raw_data_out((cvm::real*)(&msg_data[0]));
+    samples->raw_data_out((size_t*)(&msg_data[samp_start]));
+    for (p = 1; p < cvm::replica_num(); p++) {
+      cvm::replica_comm_send(msg_data, msg_total, p);
+    }
+
+  } else {
+    // All other replicas send their delta gradient and count.
+    // Calculate the delta gradient and count.
+    last_gradients->delta_grid (*gradients);
+    last_samples->delta_grid (*samples);
+
+    // Cast the raw char data to the gradient and samples.
+    last_gradients->raw_data_out((cvm::real*)(&msg_data[0]));
+    last_samples->raw_data_out((size_t*)(&msg_data[samp_start]));
+    cvm::replica_comm_send(msg_data, msg_total, 0);
+
+    // We now receive the combined gradient from Replica 0.
+    cvm::replica_comm_recv(msg_data, msg_total, 0);
+    // We sync to the combined gradient computed by Replica 0.
+    gradients->raw_data_in((cvm::real*)(&msg_data[0]));
+    samples->raw_data_in((size_t*)(&msg_data[samp_start]));
+  }
+
+  // Without a barrier it's possible that one replica starts
+  // share 2 when other replicas haven't finished share 1.
+  cvm::replica_comm_barrier();
+  // Done syncing the replicas.
+  delete[] msg_data;
+
+  // Copy the current gradient and count values into last.
+  last_gradients->copy_grid(*gradients);
+  last_samples->copy_grid(*samples);
+  shared_last_step = cvm::step_absolute();
+}
 
 void colvarbias_abf::write_gradients_samples (const std::string &prefix, bool append)
 {
@@ -268,6 +392,27 @@ void colvarbias_abf::write_gradients_samples (const std::string &prefix, bool ap
   return;
 }
 
+
+// For Tcl implementation of selection rules.
+/// Give the total number of bins for a given bias.
+int colvarbias_abf::bin_num() {
+  return samples->number_of_points(0);
+}
+/// Calculate the bin index for a given bias.
+int colvarbias_abf::current_bin() {
+  return samples->current_bin_scalar(0);
+}
+/// Give the count at a given bin index.
+int colvarbias_abf::bin_count(int bin_index) {
+  if (bin_index < 0 || bin_index >= bin_num()) {
+    cvm::error ("Error: Tried to get bin count from invalid bin index "+cvm::to_str(bin_index));
+    return -1;
+  }
+  std::vector<int> ix(1,(int)bin_index);
+  return samples->value(ix);
+}
+
+
 void colvarbias_abf::read_gradients_samples ()
 {
   std::string samples_in_name, gradients_in_name;
diff --git a/lib/colvars/colvarbias_abf.h b/lib/colvars/colvarbias_abf.h
index 6873a8f9b1..b89ca68dec 100644
--- a/lib/colvars/colvarbias_abf.h
+++ b/lib/colvars/colvarbias_abf.h
@@ -1,5 +1,3 @@
-/// -*- c++ -*-
-
 /************************************************************************
  * Headers for the ABF and histogram biases                             *
  ************************************************************************/
@@ -11,7 +9,6 @@
 #include <list>
 #include <sstream>
 #include <iomanip>
-//#include <cmath>
 
 #include "colvarbias.h"
 #include "colvargrid.h"
@@ -62,8 +59,28 @@ private:
   /// n-dim grid of number of samples
   colvar_grid_count     *samples;
 
+  // shared ABF
+  bool     shared_on;
+  size_t   shared_freq;
+  int   shared_last_step;
+  // Share between replicas -- may be called independently of update
+  virtual void replica_share();
+
+  // Store the last set for shared ABF
+  colvar_grid_gradient  *last_gradients;
+  colvar_grid_count     *last_samples;
+
+  // For Tcl implementation of selection rules.
+  /// Give the total number of bins for a given bias.
+  virtual int bin_num();
+  /// Calculate the bin index for a given bias.
+  virtual int current_bin();
+  //// Give the count at a given bin index.
+  virtual int bin_count(int bin_index);
+
   /// Write human-readable FE gradients and sample count
   void		  write_gradients_samples (const std::string &prefix, bool append = false);
+  void		  write_last_gradients_samples (const std::string &prefix, bool append = false);
 
   /// Read human-readable FE gradients and sample count (if not using restart)
   void		  read_gradients_samples ();
diff --git a/lib/colvars/colvarbias_meta.cpp b/lib/colvars/colvarbias_meta.cpp
index b49aee87c0..5e4e002ded 100644
--- a/lib/colvars/colvarbias_meta.cpp
+++ b/lib/colvars/colvarbias_meta.cpp
@@ -723,6 +723,7 @@ void colvarbias_meta::calc_hills_force (size_t const &i,
     }
     break;
 
+  case colvarvalue::type_quaternion:
   case colvarvalue::type_quaternionderiv:
     for (h = h_first; h != h_last; h++) {
       if (h->value() == 0.0) continue;
diff --git a/lib/colvars/colvarcomp.cpp b/lib/colvars/colvarcomp.cpp
index f333f5db3e..949256004e 100644
--- a/lib/colvars/colvarcomp.cpp
+++ b/lib/colvars/colvarcomp.cpp
@@ -47,11 +47,16 @@ void colvar::cvc::parse_group (std::string const &conf,
                                bool optional)
 {
   if (key_lookup (conf, group_key)) {
-    group.parse (conf, group_key);
+    if (group.parse (conf, group_key) != COLVARS_OK) {
+      cvm::error ("Error parsing definition for atom group \""+
+                         std::string (group_key)+"\".\n");
+      return;
+    }
   } else {
     if (! optional) {
-      cvm::fatal_error ("Error: definition for atom group \""+
+      cvm::error ("Error: definition for atom group \""+
                       std::string (group_key)+"\" not found.\n");
+      return;
     }
   }
 }
@@ -137,9 +142,7 @@ void colvar::cvc::debug_gradients (cvm::atom_group &group)
                              21, 14)+"\n");
       cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+
                 cvm::to_str (std::fabs (x_1 - x_0 - dx_pred) /
-                             std::fabs (x_1 - x_0),
-                             12, 5)+
-                ".\n");
+                             std::fabs (x_1 - x_0), 12, 5)+"\n");
     }
   }
 
diff --git a/lib/colvars/colvarcomp.h b/lib/colvars/colvarcomp.h
index 253c1d8de7..735c2f5bc1 100644
--- a/lib/colvars/colvarcomp.h
+++ b/lib/colvars/colvarcomp.h
@@ -219,14 +219,6 @@ public:
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
 
-  /// \brief Return a positive number if x2>x1, zero if x2==x1,
-  /// negative otherwise (can be redefined to transparently implement
-  /// constraints, symmetries and periodicities) \b Note: \b it \b
-  /// only \b works \b with \b scalar \b variables, otherwise raises
-  /// an error
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
-
   /// \brief Wrapp value (for periodic/symmetric cvcs)
   virtual void wrap (colvarvalue &x) const;
 
@@ -300,18 +292,6 @@ inline colvarvalue colvar::cvc::dist2_rgrad (colvarvalue const &x1,
   return x2.dist2_grad (x1);
 }
 
-inline cvm::real colvar::cvc::compare (colvarvalue const &x1,
-                                       colvarvalue const &x2) const
-{
-  if (this->type() == colvarvalue::type_scalar) {
-    return cvm::real (x1 - x2);
-  } else {
-    cvm::error ("Error: you requested an operation which requires "
-                "comparison between two non-scalar values.\n");
-    return 0.0;
-  }
-}
-
 inline void colvar::cvc::wrap (colvarvalue &x) const
 {
   return;
@@ -356,8 +336,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -383,9 +361,6 @@ public:
   /// Redefined to handle the box periodicity
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  /// Redefined to handle the box periodicity
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -408,8 +383,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -453,8 +426,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
   /// \brief Redefined to make use of the user-provided period
   virtual void wrap (colvarvalue &x) const;
 };
@@ -485,8 +456,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -511,8 +480,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -541,8 +508,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -565,8 +530,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -592,8 +555,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -635,8 +596,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -685,8 +644,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -736,9 +693,6 @@ public:
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
   /// Redefined to handle the 2*PI periodicity
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
-  /// Redefined to handle the 2*PI periodicity
   virtual void wrap (colvarvalue &x) const;
 };
 
@@ -796,8 +750,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 /// \brief Colvar component: self-coordination number within a group
@@ -835,8 +787,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 /// \brief Colvar component: hydrogen bond, defined as the product of
@@ -872,8 +822,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -915,8 +863,6 @@ public:
 //                                    colvarvalue const &x2) const;
 //   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
 //                                    colvarvalue const &x2) const;
-//   virtual cvm::real compare (colvarvalue const &x1,
-//                              colvarvalue const &x2) const;
 // };
 
 
@@ -958,8 +904,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 /// \brief Colvar component: dihedPC
@@ -988,8 +932,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 /// \brief Colvar component: orientation in space of an atom group,
@@ -1030,8 +972,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -1055,8 +995,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -1080,8 +1018,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -1108,8 +1044,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -1141,9 +1075,6 @@ public:
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
   /// Redefined to handle the 2*PI periodicity
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
-  /// Redefined to handle the 2*PI periodicity
   virtual void wrap (colvarvalue &x) const;
 };
 
@@ -1180,8 +1111,6 @@ public:
                                    colvarvalue const &x2) const;
   virtual colvarvalue dist2_rgrad (colvarvalue const &x1,
                                    colvarvalue const &x2) const;
-  virtual cvm::real compare (colvarvalue const &x1,
-                             colvarvalue const &x2) const;
 };
 
 
@@ -1214,12 +1143,6 @@ public:
     return this->dist2_lgrad (x2, x1);                                  \
   }                                                                     \
                                                                         \
-  inline cvm::real colvar::TYPE::compare (colvarvalue const &x1,        \
-                                          colvarvalue const &x2) const  \
-  {                                                                     \
-    return this->dist2_lgrad (x1, x2);                                  \
-  }                                                                     \
-                                                                        \
 
   simple_scalar_dist_functions (distance)
   // NOTE: distance_z has explicit functions, see below
@@ -1268,12 +1191,6 @@ inline colvarvalue colvar::dihedral::dist2_rgrad (colvarvalue const &x1,
   return (-2.0) * diff;
 }
 
-inline cvm::real colvar::dihedral::compare (colvarvalue const &x1,
-                                            colvarvalue const &x2) const
-{
-  return dist2_lgrad (x1, x2);
-}
-
 inline void colvar::dihedral::wrap (colvarvalue &x) const
 {
   if ((x.real_value - wrap_center) >= 180.0) {
@@ -1313,12 +1230,6 @@ inline colvarvalue colvar::spin_angle::dist2_rgrad (colvarvalue const &x1,
   return (-2.0) * diff;
 }
 
-inline cvm::real colvar::spin_angle::compare (colvarvalue const &x1,
-                                            colvarvalue const &x2) const
-{
-  return dist2_lgrad (x1, x2);
-}
-
 inline void colvar::spin_angle::wrap (colvarvalue &x) const
 {
   if ((x.real_value - wrap_center) >= 180.0) {
@@ -1370,12 +1281,6 @@ inline colvarvalue colvar::distance_z::dist2_rgrad (colvarvalue const &x1,
   return (-2.0) * diff;
 }
 
-inline cvm::real colvar::distance_z::compare (colvarvalue const &x1,
-                                              colvarvalue const &x2) const
-{
-  return dist2_lgrad (x1, x2);
-}
-
 inline void colvar::distance_z::wrap (colvarvalue &x) const
 {
   if (! this->b_periodic) {
@@ -1412,13 +1317,6 @@ inline colvarvalue colvar::distance_vec::dist2_rgrad (colvarvalue const &x1,
   return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value);
 }
 
-inline cvm::real colvar::distance_vec::compare (colvarvalue const &x1,
-                                                colvarvalue const &x2) const
-{
-  cvm::error ("Error: cannot compare() two distance vectors.\n");
-  return 0.0;
-}
-
 inline cvm::real colvar::distance_dir::dist2 (colvarvalue const &x1,
                                               colvarvalue const &x2) const
 {
@@ -1437,13 +1335,6 @@ inline colvarvalue colvar::distance_dir::dist2_rgrad (colvarvalue const &x1,
   return colvarvalue ((x2.rvector_value - x1.rvector_value), colvarvalue::type_unitvector);
 }
 
-inline cvm::real colvar::distance_dir::compare (colvarvalue const &x1,
-                                                colvarvalue const &x2) const
-{
-  cvm::error ("Error: cannot compare() two distance directions.\n");
-  return 0.0;
-}
-
 // distance between quaternions
 
 inline cvm::real colvar::orientation::dist2 (colvarvalue const &x1,
@@ -1464,12 +1355,5 @@ inline colvarvalue colvar::orientation::dist2_rgrad (colvarvalue const &x1,
   return x2.quaternion_value.dist2_grad (x1);
 }
 
-inline cvm::real colvar::orientation::compare (colvarvalue const &x1,
-                                               colvarvalue const &x2) const
-{
-  cvm::error ("Error: cannot compare() two quaternions.\n");
-  return 0.0;
-}
-
 
 #endif
diff --git a/lib/colvars/colvarcomp_distances.cpp b/lib/colvars/colvarcomp_distances.cpp
index 3e1163db4b..43bfebf188 100644
--- a/lib/colvars/colvarcomp_distances.cpp
+++ b/lib/colvars/colvarcomp_distances.cpp
@@ -725,7 +725,7 @@ colvar::rmsd::rmsd (std::string const &conf)
     return;
   }
 
-  if (atoms.ref_pos_group != NULL) {
+  if (atoms.ref_pos_group != NULL && b_Jacobian_derivative) {
     cvm::log ("The option \"refPositionsGroup\" (alternative group for fitting) was enabled: "
               "Jacobian derivatives of the RMSD will not be calculated.\n");
     b_Jacobian_derivative = false;
@@ -788,10 +788,21 @@ colvar::rmsd::rmsd (std::string const &conf)
     atoms.ref_pos = ref_pos;
     atoms.center_ref_pos();
 
+    cvm::log ("This is a standard minimum RMSD, derivatives of the optimal rotation "
+              "will not be computed as they cancel out in the gradients.");
+    atoms.b_fit_gradients = false;
+  }
+
+  if (atoms.b_rotate) {
+    // TODO: finer-grained control of this would require exposing a
+    // "request_Jacobian_derivative()" method to the colvar, and the same
+    // from the colvar to biases
+    // TODO: this should not be enabled here anyway, as it is not specific of the
+    // component - instead it should be decided in a generic way by the atom group
+
     // request the calculation of the derivatives of the rotation defined by the atom group
     atoms.rot.request_group1_gradients (atoms.size());
     // request derivatives of optimal rotation wrt reference coordinates for Jacobian:
-    // this is only required for ABF, but we do both groups here for better caching
     atoms.rot.request_group2_gradients (atoms.size());
   }
 }
diff --git a/lib/colvars/colvargrid.h b/lib/colvars/colvargrid.h
index c3a61dcaa0..7cc255ee74 100644
--- a/lib/colvars/colvargrid.h
+++ b/lib/colvars/colvargrid.h
@@ -362,6 +362,70 @@ public:
     has_data = true;
   }
 
+ /// \brief Get the change from this to other_grid
+  /// and store the result in this.
+  /// this_grid := other_grid - this_grid
+  /// Grids must have the same dimensions.
+  void delta_grid (colvar_grid<T> const &other_grid)
+  {
+
+    if (other_grid.multiplicity() != this->multiplicity()) {
+      cvm::error ("Error: trying to subtract two grids with "
+                        "different multiplicity.\n");
+      return;
+	}	
+
+    if (other_grid.data.size() != this->data.size()) {
+      cvm::error ("Error: trying to subtract two grids with "
+                        "different size.\n");
+      return;
+    }
+
+    for (size_t i = 0; i < data.size(); i++) {
+      data[i] = other_grid.data[i] - data[i];
+    }
+    has_data = true;
+  }
+
+  /// \brief Copy data from another grid of the same type, AND
+  /// identical definition (boundaries, widths)
+  /// Added for shared ABF.
+  void copy_grid (colvar_grid<T> const &other_grid)
+  {
+    if (other_grid.multiplicity() != this->multiplicity()) {
+      cvm::error ("Error: trying to copy two grids with "
+                        "different multiplicity.\n");
+	  return;    
+	}
+
+    if (other_grid.data.size() != this->data.size()) {
+      cvm::error ("Error: trying to copy two grids with "
+                        "different size.\n");
+      return;
+    }
+
+
+    for (size_t i = 0; i < data.size(); i++) {
+      data[i] = other_grid.data[i];
+    }
+    has_data = true;
+  }
+
+  /// \brief Extract the grid data as they are represented in memory.
+  /// Put the results in "out_data".
+  void raw_data_out (T* out_data) const
+  {
+    for (size_t i = 0; i < data.size(); i++) out_data[i] = data[i];
+  }
+  /// \brief Input the data as they are represented in memory.
+  void raw_data_in (const T* in_data)
+  {
+    for (size_t i = 0; i < data.size(); i++) data[i] = in_data[i];
+    has_data = true;
+  }
+  /// \brief Size of the data as they are represented in memory.
+  size_t raw_data_num() const { return data.size(); }
+
 
   /// \brief Get the binned value indexed by ix, or the first of them
   /// if the multiplicity is larger than 1
diff --git a/lib/colvars/colvarmodule.cpp b/lib/colvars/colvarmodule.cpp
index 3b85273a60..03f9ba704c 100644
--- a/lib/colvars/colvarmodule.cpp
+++ b/lib/colvars/colvarmodule.cpp
@@ -99,7 +99,7 @@ int colvarmodule::config (std::string &conf)
   // parse global options
   error_code |= parse_global_params (conf);
 
-  if (error_code != COLVARS_OK) {
+  if (error_code != COLVARS_OK || cvm::get_error()) {
     set_error_bits(INPUT_ERROR);
     return COLVARS_ERROR;
   }
@@ -107,13 +107,23 @@ int colvarmodule::config (std::string &conf)
   // parse the options for collective variables
   error_code |= parse_colvars (conf);
 
+  if (error_code != COLVARS_OK || cvm::get_error()) {
+    set_error_bits(INPUT_ERROR);
+    return COLVARS_ERROR;
+  }
+
   // parse the options for biases
   error_code |= parse_biases (conf);
 
+  if (error_code != COLVARS_OK || cvm::get_error()) {
+    set_error_bits(INPUT_ERROR);
+    return COLVARS_ERROR;
+  }
+
   // done parsing known keywords, check that all keywords found were valid ones
   error_code |= parse->check_keywords (conf, "colvarmodule");
 
-  if (error_code != COLVARS_OK) {
+  if (error_code != COLVARS_OK || cvm::get_error()) {
     set_error_bits(INPUT_ERROR);
     return COLVARS_ERROR;
   }
@@ -179,12 +189,11 @@ int colvarmodule::parse_colvars (std::string const &conf)
       cvm::log (cvm::line_marker);
       cvm::increase_depth();
       colvars.push_back (new colvar (colvar_conf));
-      if (cvm::get_error()) {
-        delete colvars.back();
-        colvars.pop_back();
-        return COLVARS_ERROR;
-      }
-      if ((colvars.back())->check_keywords (colvar_conf, "colvar") != COLVARS_OK) {
+      if (cvm::get_error() ||
+          ((colvars.back())->check_keywords (colvar_conf, "colvar") != COLVARS_OK)) {
+            cvm::log("Error while constructing colvar number " +
+        cvm::to_str(colvars.size()) + " : deleting.");
+        delete colvars.back();  // the colvar destructor updates the colvars array
         return COLVARS_ERROR;
       }
       cvm::decrease_depth();
@@ -192,6 +201,7 @@ int colvarmodule::parse_colvars (std::string const &conf)
       cvm::error("Error: \"colvar\" keyword found without any configuration.\n", INPUT_ERROR);
       return COLVARS_ERROR;
     }
+    cvm::decrease_depth();
     colvar_conf = "";
   }
 
@@ -208,6 +218,17 @@ int colvarmodule::parse_colvars (std::string const &conf)
   return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK);
 }
 
+bool colvarmodule::check_new_bias(std::string &conf, char const *key)
+{
+  if (cvm::get_error() ||
+     (biases.back()->check_keywords(conf, key) != COLVARS_OK)) {
+    cvm::log("Error while constructing bias number " +
+        cvm::to_str(biases.size()) + " : deleting.\n");
+    delete biases.back(); // the bias destructor updates the biases array
+    return true;
+  }
+  return false;
+}
 
 int colvarmodule::parse_biases (std::string const &conf)
 {
@@ -223,12 +244,7 @@ int colvarmodule::parse_biases (std::string const &conf)
         cvm::log (cvm::line_marker);
         cvm::increase_depth();
         biases.push_back (new colvarbias_abf (abf_conf, "abf"));
-        if (cvm::get_error()) {
-          delete biases.back();
-          biases.pop_back();
-          return COLVARS_ERROR;
-        }
-        if ((biases.back())->check_keywords (abf_conf, "abf") != COLVARS_OK) {
+        if (cvm::check_new_bias(abf_conf, "abf")) {
           return COLVARS_ERROR;
         }
         cvm::decrease_depth();
@@ -250,12 +266,7 @@ int colvarmodule::parse_biases (std::string const &conf)
         cvm::log (cvm::line_marker);
         cvm::increase_depth();
         biases.push_back (new colvarbias_restraint_harmonic (harm_conf, "harmonic"));
-        if (cvm::get_error()) {
-          delete biases.back();
-          biases.pop_back();
-          return COLVARS_ERROR;
-        }
-        if ((biases.back())->check_keywords (harm_conf, "harmonic") != COLVARS_OK) {
+        if (cvm::check_new_bias(harm_conf, "harmonic")) {
           return COLVARS_ERROR;
         }
         cvm::decrease_depth();
@@ -277,12 +288,7 @@ int colvarmodule::parse_biases (std::string const &conf)
         cvm::log (cvm::line_marker);
         cvm::increase_depth();
         biases.push_back (new colvarbias_restraint_linear (lin_conf, "linear"));
-        if (cvm::get_error()) {
-          delete biases.back();
-          biases.pop_back();
-          return COLVARS_ERROR;
-        }
-        if ((biases.back())->check_keywords (lin_conf, "linear") != COLVARS_OK) {
+        if (cvm::check_new_bias(lin_conf, "linear")) {
           return COLVARS_ERROR;
         }
         cvm::decrease_depth();
@@ -304,12 +310,7 @@ int colvarmodule::parse_biases (std::string const &conf)
         cvm::log (cvm::line_marker);
         cvm::increase_depth();
         biases.push_back (new colvarbias_alb (alb_conf, "ALB"));
-        if (cvm::get_error()) {
-          delete biases.back();
-          biases.pop_back();
-          return COLVARS_ERROR;
-        }
-        if ((biases.back())->check_keywords (alb_conf, "ALB") != COLVARS_OK) {
+        if (cvm::check_new_bias(alb_conf, "ALB")) {
           return COLVARS_ERROR;
         }
         cvm::decrease_depth();
@@ -332,12 +333,7 @@ int colvarmodule::parse_biases (std::string const &conf)
         cvm::log (cvm::line_marker);
         cvm::increase_depth();
         biases.push_back (new colvarbias_histogram (histo_conf, "histogram"));
-        if (cvm::get_error()) {
-          delete biases.back();
-          biases.pop_back();
-          return COLVARS_ERROR;
-        }
-        if ((biases.back())->check_keywords (histo_conf, "histogram") != COLVARS_OK) {
+        if (cvm::check_new_bias(histo_conf, "histogram")) {
           return COLVARS_ERROR;
         }
         cvm::decrease_depth();
@@ -359,12 +355,7 @@ int colvarmodule::parse_biases (std::string const &conf)
         cvm::log (cvm::line_marker);
         cvm::increase_depth();
         biases.push_back (new colvarbias_meta (meta_conf, "metadynamics"));
-        if (cvm::get_error()) {
-          delete biases.back();
-          biases.pop_back();
-          return COLVARS_ERROR;
-        }
-        if ((biases.back())->check_keywords (meta_conf, "metadynamics") != COLVARS_OK) {
+        if (cvm::check_new_bias(meta_conf, "metadynamics")) {
           return COLVARS_ERROR;
         }
         cvm::decrease_depth();
@@ -444,7 +435,6 @@ std::string colvarmodule::read_colvar(std::string const &name)
   return ss.str();
 }
 
-
 cvm::real colvarmodule::energy_difference (std::string const &bias_name,
                                            std::string const &conf)
 {
@@ -458,6 +448,125 @@ cvm::real colvarmodule::energy_difference (std::string const &bias_name,
   return energy_diff;
 }
 
+// For shared ABF
+cvm::real colvarmodule::read_width(std::string const &name)
+{
+  cvm::increase_depth();
+  int found = 0;
+  real width = -1.0;
+  for (std::vector<colvar *>::iterator cvi = colvars.begin();
+       cvi != colvars.end();
+       cvi++) {
+    if ( (*cvi)->name == name ) {
+      ++found;
+      width = (*cvi)->width;
+    }
+  }
+  if (found < 1) {
+    cvm::error ("Error: bias not found.\n");
+  } else if (found > 1) {
+    cvm::error ("Error: duplicate bias name.\n");
+  } else {
+    cvm::decrease_depth();
+  }
+  return width;
+}
+
+size_t colvarmodule::bias_current_bin (std::string const &bias_name)
+{
+  cvm::increase_depth();
+  int found = 0;
+  size_t ret = 0; // N.B.: size_t is unsigned, so returning -1 would be a problem.
+
+  for (std::vector<colvarbias *>::iterator bi = biases.begin();
+       bi != biases.end();
+       bi++) {
+    if ( (*bi)->name == bias_name ) {
+      ++found;
+      ret = (*bi)->current_bin ();
+    }
+  }
+  if (found < 1) {
+    cvm::error ("Error: bias not found.\n");
+  } else if (found > 1) {
+    cvm::error ("Error: duplicate bias name.\n");
+  } else {
+    cvm::decrease_depth();
+  }
+  return ret;
+}
+
+size_t colvarmodule::bias_bin_num (std::string const &bias_name)
+{
+  cvm::increase_depth();
+  int found = 0;
+  size_t ret = 0; // N.B.: size_t is unsigned, so returning -1 would be a problem.
+
+  for (std::vector<colvarbias *>::iterator bi = biases.begin();
+       bi != biases.end();
+       bi++) {
+    if ( (*bi)->name == bias_name ) {
+      ++found;
+      ret = (*bi)->bin_num ();
+    }
+  }
+  if (found < 1) {
+    cvm::error ("Error: bias not found.\n");
+  } else if (found > 1) {
+    cvm::error ("Error: duplicate bias name.\n");
+  } else {
+    cvm::decrease_depth();
+  }
+  return ret;
+}
+
+size_t colvarmodule::bias_bin_count (std::string const &bias_name, size_t bin_index)
+{
+  cvm::increase_depth();
+  int found = 0;
+  size_t ret = 0; // N.B.: size_t is unsigned, so returning -1 would be a problem.
+
+  for (std::vector<colvarbias *>::iterator bi = biases.begin();
+       bi != biases.end();
+       bi++) {
+    if ( (*bi)->name == bias_name ) {
+      ++found;
+      ret = (*bi)->bin_count (bin_index);
+    }
+  }
+  if (found < 1) {
+    cvm::error ("Error: bias not found.\n");
+  } else if (found > 1) {
+    cvm::error ("Error: duplicate bias name.\n");
+  } else {
+    cvm::decrease_depth();
+  }
+  return ret;
+}
+
+void colvarmodule::bias_share (std::string const &bias_name)
+{
+  cvm::increase_depth();
+  int found = 0;
+
+  for (std::vector<colvarbias *>::iterator bi = biases.begin();
+       bi != biases.end();
+       bi++) {
+    if ( (*bi)->name == bias_name ) {
+      ++found;
+      (*bi)->replica_share ();
+    }
+  }
+  if (found < 1) {
+    cvm::error ("Error: bias not found.\n");
+    return;
+  }
+  if (found > 1) {
+    cvm::error ("Error: duplicate bias name.\n");
+    return;
+  }
+  cvm::decrease_depth();
+}
 
 
 int colvarmodule::calc() {
@@ -675,21 +784,20 @@ colvarmodule::~colvarmodule()
 
 int colvarmodule::reset()
 {
-  if (cvm::debug())
-    cvm::log ("colvars::reset() called.\n");
-  for (std::vector<colvar *>::iterator cvi = colvars.begin();
-       cvi != colvars.end();
+  cvm::log("Resetting the Collective Variables Module.\n");
+  // Iterate backwards because we are deleting the elements as we go
+  for (std::vector<colvar *>::reverse_iterator cvi = colvars.rbegin();
+       cvi != colvars.rend();
        cvi++) {
-    delete *cvi;
-    cvi--;
+    delete *cvi; // the colvar destructor updates the colvars array
   }
   colvars.clear();
 
-  for (std::vector<colvarbias *>::iterator bi = biases.begin();
-       bi != biases.end();
+  // Iterate backwards because we are deleting the elements as we go
+  for (std::vector<colvarbias *>::reverse_iterator bi = biases.rbegin();
+       bi != biases.rend();
        bi++) {
-    delete *bi;
-    bi--;
+    delete *bi; // the bias destructor updates the biases array
   }
   biases.clear();
 
diff --git a/lib/colvars/colvarmodule.h b/lib/colvars/colvarmodule.h
index fab6ae5802..ba1a4937e9 100644
--- a/lib/colvars/colvarmodule.h
+++ b/lib/colvars/colvarmodule.h
@@ -4,7 +4,7 @@
 #define COLVARMODULE_H
 
 #ifndef COLVARS_VERSION
-#define COLVARS_VERSION "2014-10-07"
+#define COLVARS_VERSION "2014-10-21"
 #endif
 
 #ifndef COLVARS_DEBUG
@@ -219,6 +219,9 @@ public:
   /// Parse and initialize collective variable biases
   int parse_biases (std::string const &conf);
 
+  /// Test error condition and keyword parsing
+  /// on error, delete new bias
+  bool check_new_bias(std::string &conf, char const *key);
 
   // "Setup" functions (change internal data based on related data
   // from the proxy that may change during program execution)
@@ -270,6 +273,17 @@ public:
   /// currently works for harmonic (force constant and/or centers)
   real energy_difference (std::string const &bias_name, std::string const &conf);
 
+  /// Give the bin width in the units of the colvar.
+  real read_width(std::string const &name);
+  /// Give the total number of bins for a given bias.
+  size_t bias_bin_num(std::string const &bias_name);
+  /// Calculate the bin index for a given bias.
+  size_t bias_current_bin(std::string const &bias_name);
+  //// Give the count at a given bin index.
+  size_t bias_bin_count(std::string const &bias_name, size_t bin_index);
+  //// Share among replicas.
+  void bias_share(std::string const &bias_name);
+
   /// Calculate collective variables and biases
   int calc();
 
@@ -346,6 +360,13 @@ public:
   /// Print a message to the main log and exit normally
   static void exit (std::string const &message);
 
+  // Replica exchange commands.
+  static bool replica_enabled();
+  static int replica_index();
+  static int replica_num();
+  static void replica_comm_barrier();
+  static int replica_comm_recv(char* msg_data, int buf_len, int src_rep);
+  static int replica_comm_send(char* msg_data, int msg_len, int dest_rep);
 
   /// \brief Get the distance between two atomic positions with pbcs handled
   /// correctly
@@ -533,6 +554,27 @@ inline cvm::real cvm::dt()
   return proxy->dt();
 }
 
+// Replica exchange commands
+inline bool cvm::replica_enabled() {
+  return proxy->replica_enabled();
+}
+inline int cvm::replica_index() {
+  return proxy->replica_index();
+}
+inline int cvm::replica_num() {
+  return proxy->replica_num();
+}
+inline void cvm::replica_comm_barrier() {
+  return proxy->replica_comm_barrier();
+}
+inline int cvm::replica_comm_recv(char* msg_data, int buf_len, int src_rep) {
+  return proxy->replica_comm_recv(msg_data,buf_len,src_rep);
+}
+inline int cvm::replica_comm_send(char* msg_data, int msg_len, int dest_rep) {
+  return proxy->replica_comm_send(msg_data,msg_len,dest_rep);
+}
+
+
 inline void cvm::request_system_force()
 {
   proxy->request_system_force (true);
diff --git a/lib/colvars/colvarproxy.h b/lib/colvars/colvarproxy.h
index 89c229dde3..ec458d4867 100644
--- a/lib/colvars/colvarproxy.h
+++ b/lib/colvars/colvarproxy.h
@@ -5,7 +5,7 @@
 
 
 #ifndef COLVARPROXY_VERSION
-#define COLVARPROXY_VERSION "2014-09-19"
+#define COLVARPROXY_VERSION "2014-10-21"
 #endif
 
 
@@ -68,8 +68,31 @@ public:
   virtual int frame (int) { return COLVARS_NOT_IMPLEMENTED; }
 
 
-  // **************** SIMULATION PARAMETERS ****************
+  // Replica exchange commands:
+
+  /// \brief Indicate if multi-replica support is available and active
+  virtual bool replica_enabled() { return false; }
+
+  /// \brief Index of this replica
+  virtual int replica_index() { return 0; }
 
+  /// \brief Total number of replica
+  virtual int replica_num() { return 1; }
+
+  /// \brief Synchronize replica
+  virtual void replica_comm_barrier() {}
+
+  /// \brief Receive data from other replica
+  virtual int replica_comm_recv(char* msg_data, int buf_len, int src_rep) {
+    return COLVARS_NOT_IMPLEMENTED;
+  }
+
+  /// \brief Send data to other replica
+  virtual int replica_comm_send(char* msg_data, int msg_len, int dest_rep) {
+    return COLVARS_NOT_IMPLEMENTED;
+  }
+
+  // **************** SIMULATION PARAMETERS ****************
 
   /// \brief Prefix to be used for input files (restarts, not
   /// configuration)
@@ -93,7 +116,7 @@ public:
     return output_prefix_str;
   }
 
-  /// \brief Restarts will be fritten each time this number of steps has passed
+  /// \brief Restarts will be written each time this number of steps has passed
   virtual size_t restart_frequency() = 0;
 
 
@@ -212,4 +235,3 @@ inline cvm::real colvarproxy::position_dist2 (cvm::atom_pos const &pos1,
 }
 
 #endif
-
diff --git a/lib/colvars/colvarscript.cpp b/lib/colvars/colvarscript.cpp
index 5b6c333f7a..13dffd35d1 100644
--- a/lib/colvars/colvarscript.cpp
+++ b/lib/colvars/colvarscript.cpp
@@ -214,10 +214,7 @@ int colvarscript::proc_colvar (int argc, char const *argv[]) {
   }
 
   if (subcmd == "update") {
-    // note: this is not sufficient for a newly created colvar
-    // as atom coordinates may not be properly loaded
-    // a full CVM update is required
-    // or otherwise updating atom positions
+    cv->calc();
     cv->update();
     result = cvm::to_str(cv->value(), 0, cvm::cv_prec);
     return COLVARSCRIPT_OK;
diff --git a/lib/colvars/colvartypes.cpp b/lib/colvars/colvartypes.cpp
index 53dc1c1c28..b24be512a1 100644
--- a/lib/colvars/colvartypes.cpp
+++ b/lib/colvars/colvartypes.cpp
@@ -350,22 +350,22 @@ void colvarmodule::rotation::calc_optimal_rotation
 
     // derivative of the S matrix
     ds_1.reset();
-    ds_1[0][0] = cvm::rvector ( a2x,  a2y,  a2z);
-    ds_1[1][0] = cvm::rvector ( 0.0,  a2z, -a2y);
+    ds_1[0][0].set( a2x,  a2y,  a2z);
+    ds_1[1][0].set( 0.0,  a2z, -a2y);
     ds_1[0][1] = ds_1[1][0];
-    ds_1[2][0] = cvm::rvector (-a2z,  0.0,  a2x);
+    ds_1[2][0].set(-a2z,  0.0,  a2x);
     ds_1[0][2] = ds_1[2][0];
-    ds_1[3][0] = cvm::rvector ( a2y, -a2x,  0.0);
+    ds_1[3][0].set( a2y, -a2x,  0.0);
     ds_1[0][3] = ds_1[3][0];
-    ds_1[1][1] = cvm::rvector ( a2x, -a2y, -a2z);
-    ds_1[2][1] = cvm::rvector ( a2y,  a2x,  0.0);
+    ds_1[1][1].set( a2x, -a2y, -a2z);
+    ds_1[2][1].set( a2y,  a2x,  0.0);
     ds_1[1][2] = ds_1[2][1];
-    ds_1[3][1] = cvm::rvector ( a2z,  0.0,  a2x);
+    ds_1[3][1].set( a2z,  0.0,  a2x);
     ds_1[1][3] = ds_1[3][1];
-    ds_1[2][2] = cvm::rvector (-a2x,  a2y, -a2z);
-    ds_1[3][2] = cvm::rvector ( 0.0,  a2z,  a2y);
+    ds_1[2][2].set(-a2x,  a2y, -a2z);
+    ds_1[3][2].set( 0.0,  a2z,  a2y);
     ds_1[2][3] = ds_1[3][2];
-    ds_1[3][3] = cvm::rvector (-a2x, -a2y,  a2z);
+    ds_1[3][3].set(-a2x, -a2y,  a2z);
 
     cvm::rvector              &dl0_1 = dL0_1[ia];
     vector1d<cvm::rvector, 4> &dq0_1 = dQ0_1[ia];
@@ -404,22 +404,22 @@ void colvarmodule::rotation::calc_optimal_rotation
     matrix2d<cvm::rvector, 4, 4> &ds_2 =  dS_2[ia];
 
     ds_2.reset();
-    ds_2[0][0] = cvm::rvector ( a1x,  a1y,  a1z);
-    ds_2[1][0] = cvm::rvector ( 0.0, -a1z,  a1y);
+    ds_2[0][0].set( a1x,  a1y,  a1z);
+    ds_2[1][0].set( 0.0, -a1z,  a1y);
     ds_2[0][1] = ds_2[1][0];
-    ds_2[2][0] = cvm::rvector ( a1z,  0.0, -a1x);
+    ds_2[2][0].set( a1z,  0.0, -a1x);
     ds_2[0][2] = ds_2[2][0];
-    ds_2[3][0] = cvm::rvector (-a1y,  a1x,  0.0);
+    ds_2[3][0].set(-a1y,  a1x,  0.0);
     ds_2[0][3] = ds_2[3][0];
-    ds_2[1][1] = cvm::rvector ( a1x, -a1y, -a1z);
-    ds_2[2][1] = cvm::rvector ( a1y,  a1x,  0.0);
+    ds_2[1][1].set( a1x, -a1y, -a1z);
+    ds_2[2][1].set( a1y,  a1x,  0.0);
     ds_2[1][2] = ds_2[2][1];
-    ds_2[3][1] = cvm::rvector ( a1z,  0.0,  a1x);
+    ds_2[3][1].set( a1z,  0.0,  a1x);
     ds_2[1][3] = ds_2[3][1];
-    ds_2[2][2] = cvm::rvector (-a1x,  a1y, -a1z);
-    ds_2[3][2] = cvm::rvector ( 0.0,  a1z,  a1y);
+    ds_2[2][2].set(-a1x,  a1y, -a1z);
+    ds_2[3][2].set( 0.0,  a1z,  a1y);
     ds_2[2][3] = ds_2[3][2];
-    ds_2[3][3] = cvm::rvector (-a1x, -a1y,  a1z);
+    ds_2[3][3].set(-a1x, -a1y,  a1z);
 
     cvm::rvector              &dl0_2 = dL0_2[ia];
     vector1d<cvm::rvector, 4> &dq0_2 = dQ0_2[ia];
diff --git a/lib/colvars/colvartypes.h b/lib/colvars/colvartypes.h
index 0d97740622..18a6de3cfb 100644
--- a/lib/colvars/colvartypes.h
+++ b/lib/colvars/colvartypes.h
@@ -37,10 +37,19 @@ public:
   {}
 
   /// \brief Set all components to a scalar value
-  inline void set (cvm::real const &value = 0.0) {
+  inline void set (cvm::real const &value) {
     x = y = z = value;
   }
 
+  /// \brief Assign all components
+  inline void set (cvm::real const &x_i,
+                   cvm::real const &y_i,
+                   cvm::real const &z_i) {
+    x = x_i;
+    y = y_i;
+    z = z_i;
+  }
+
   /// \brief Set all components to zero
   inline void reset() {
     x = y = z = 0.0;
-- 
GitLab