diff --git a/lib/colvars/colvar.cpp b/lib/colvars/colvar.cpp index aafa60e1f..852cc7984 100644 --- a/lib/colvars/colvar.cpp +++ b/lib/colvars/colvar.cpp @@ -1,1853 +1,1898 @@ /// -*- c++ -*- #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" #include "colvar.h" #include "colvarcomp.h" #include "colvarscript.h" #include -colvar::colvar (std::string const &conf) +colvar::colvar(std::string const &conf) { size_t i, j; - cvm::log ("Initializing a new collective variable.\n"); + cvm::log("Initializing a new collective variable.\n"); - get_keyval (conf, "name", this->name, - (std::string ("colvar")+cvm::to_str (cvm::colvars.size()+1))); + get_keyval(conf, "name", this->name, + (std::string("colvar")+cvm::to_str(cvm::colvars.size()+1))); - if (cvm::colvar_by_name (this->name) != NULL) { - cvm::error ("Error: this colvar cannot have the same name, \""+this->name+ + if (cvm::colvar_by_name(this->name) != NULL) { + cvm::error("Error: this colvar cannot have the same name, \""+this->name+ "\", as another colvar.\n", INPUT_ERROR); } // all tasks disabled by default for (i = 0; i < task_ntot; i++) { tasks[i] = false; } kinetic_energy = 0.0; potential_energy = 0.0; // read the configuration and set up corresponding instances, for // each type of component implemented #define initialize_components(def_desc,def_config_key,def_class_name) \ { \ size_t def_count = 0; \ std::string def_conf = ""; \ size_t pos = 0; \ - while ( this->key_lookup (conf, \ + while ( this->key_lookup(conf, \ def_config_key, \ def_conf, \ pos) ) { \ if (!def_conf.size()) continue; \ - cvm::log ("Initializing " \ - "a new \""+std::string (def_config_key)+"\" component"+ \ + cvm::log("Initializing " \ + "a new \""+std::string(def_config_key)+"\" component"+ \ (cvm::debug() ? ", with configuration:\n"+def_conf \ : ".\n")); \ cvm::increase_depth(); \ - cvc *cvcp = new colvar::def_class_name (def_conf); \ + cvc *cvcp = new colvar::def_class_name(def_conf); \ if (cvcp != NULL) { \ - cvcs.push_back (cvcp); \ - cvcp->check_keywords (def_conf, def_config_key); \ + 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 \"" \ 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")) && \ - (cvcp->function_type != std::string ("dihedral")) && \ - (cvcp->function_type != std::string ("spin_angle")) ) { \ - cvm::error ("Error: invalid use of period and/or " \ + if ( (cvcp->function_type != std::string("distance_z")) && \ + (cvcp->function_type != std::string("dihedral")) && \ + (cvcp->function_type != std::string("spin_angle")) ) { \ + cvm::error("Error: invalid use of period and/or " \ "wrapAround in a \""+ \ - std::string (def_config_key)+ \ + std::string(def_config_key)+ \ "\" component.\n"+ \ "Period: "+cvm::to_str(cvcp->period) + \ " wrapAround: "+cvm::to_str(cvcp->wrap_center), \ INPUT_ERROR); \ return; \ } \ } \ if ( ! cvcs.back()->name.size()) \ - cvcs.back()->name = std::string (def_config_key)+ \ - (cvm::to_str (++def_count)); \ + cvcs.back()->name = std::string(def_config_key)+ \ + (cvm::to_str(++def_count)); \ if (cvm::debug()) \ - cvm::log ("Done initializing a \""+ \ - std::string (def_config_key)+ \ + cvm::log("Done initializing a \""+ \ + std::string(def_config_key)+ \ "\" component"+ \ (cvm::debug() ? \ ", named \""+cvcs.back()->name+"\"" \ : "")+".\n"); \ def_conf = ""; \ if (cvm::debug()) \ - cvm::log ("Parsed "+cvm::to_str (cvcs.size())+ \ + cvm::log("Parsed "+cvm::to_str(cvcs.size())+ \ " components at this time.\n"); \ } \ } - initialize_components ("distance", "distance", distance); - initialize_components ("distance vector", "distanceVec", distance_vec); - initialize_components ("distance vector " + initialize_components("distance", "distance", distance); + initialize_components("distance vector", "distanceVec", distance_vec); + initialize_components("Cartesian coordinates", "cartesian", cartesian); + initialize_components("distance vector " "direction", "distanceDir", distance_dir); - initialize_components ("distance projection " + initialize_components("distance projection " "on an axis", "distanceZ", distance_z); - initialize_components ("distance projection " + initialize_components("distance projection " "on a plane", "distanceXY", distance_xy); - initialize_components ("average distance weighted by inverse power", + initialize_components("average distance weighted by inverse power", "distanceInv", distance_inv); + initialize_components("N1xN2-long vector of pairwise distances", + "distancePairs", distance_pairs); - initialize_components ("coordination " + initialize_components("coordination " "number", "coordNum", coordnum); - initialize_components ("self-coordination " + initialize_components("self-coordination " "number", "selfCoordNum", selfcoordnum); - initialize_components ("angle", "angle", angle); - initialize_components ("dihedral", "dihedral", dihedral); + initialize_components("angle", "angle", angle); + initialize_components("dihedral", "dihedral", dihedral); - initialize_components ("hydrogen bond", "hBond", h_bond); + initialize_components("hydrogen bond", "hBond", h_bond); // initialize_components ("alpha helix", "alphaDihedrals", alpha_dihedrals); - initialize_components ("alpha helix", "alpha", alpha_angles); + initialize_components("alpha helix", "alpha", alpha_angles); - initialize_components ("dihedral principal " + initialize_components("dihedral principal " "component", "dihedralPC", dihedPC); - initialize_components ("orientation", "orientation", orientation); - initialize_components ("orientation " + initialize_components("orientation", "orientation", orientation); + initialize_components("orientation " "angle", "orientationAngle",orientation_angle); - initialize_components ("orientation " + initialize_components("orientation " "projection", "orientationProj",orientation_proj); - initialize_components ("tilt", "tilt", tilt); - initialize_components ("spin angle", "spinAngle", spin_angle); + initialize_components("tilt", "tilt", tilt); + initialize_components("spin angle", "spinAngle", spin_angle); - initialize_components ("RMSD", "rmsd", rmsd); + initialize_components("RMSD", "rmsd", rmsd); // initialize_components ("logarithm of MSD", "logmsd", logmsd); - initialize_components ("radius of " + initialize_components("radius of " "gyration", "gyration", gyration); - initialize_components ("moment of " + initialize_components("moment of " "inertia", "inertia", inertia); - initialize_components ("moment of inertia around an axis", + initialize_components("moment of inertia around an axis", "inertiaZ", inertia_z); - initialize_components ("eigenvector", "eigenvector", eigenvector); + initialize_components("eigenvector", "eigenvector", eigenvector); if (!cvcs.size()) { - cvm::error ("Error: no valid components were provided " + cvm::error("Error: no valid components were provided " "for this collective variable.\n", INPUT_ERROR); } - cvm::log ("All components initialized.\n"); + cvm::log("All components initialized.\n"); // Setup colvar as scripted function of components - if (get_keyval (conf, "scriptedFunction", scripted_function, + if (get_keyval(conf, "scriptedFunction", scripted_function, "", colvarparse::parse_silent)) { enable(task_scripted); cvm::log("This colvar uses scripted function \"" + scripted_function + "\"."); - // 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()); + std::string type_str; + get_keyval(conf, "scriptedFunctionType", type_str, "scalar"); + + x.type(colvarvalue::type_notset); + int t; + for (t = 0; t < colvarvalue::type_all; t++) { + if (type_str == colvarvalue::type_keyword(colvarvalue::Type(t))) { + x.type(colvarvalue::Type(t)); + 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())); + + if (x.type() == colvarvalue::type_vector) { + int size; + if (!get_keyval(conf, "scriptedFunctionVectorSize", size)) { + cvm::error("Error: no size specified for vector scripted function."); + return; + } + x.vector1d_value.resize(size); + } // Sort array of cvcs based on values of componentExp std::vector temp_vec; for (i = 1; i <= cvcs.size(); i++) { for (j = 0; j < cvcs.size(); j++) { if (cvcs[j]->sup_np == int(i)) { temp_vec.push_back(cvcs[j]); break; } } } if (temp_vec.size() != cvcs.size()) { cvm::error("Could not find order numbers for all components " "in componentExp values."); return; } cvcs = temp_vec; // 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()); + sorted_cvc_values.push_back(&(cvcs[j]->value())); } - } - 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])->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 { - b_single_cvc = false; + b_homogeneous = false; + // Scripted functions are deemed non-periodic b_periodic = false; period = 0.0; + b_inverse_gradients = false; + b_Jacobian_force = false; } - // check the available features of each cvc - for (i = 0; i < cvcs.size(); i++) { + if (!tasks[task_scripted]) { + colvarvalue const &cvc_value = (cvcs[0])->value(); + if (cvm::debug()) + cvm::log ("This collective variable is a "+ + colvarvalue::type_desc(cvc_value.type())+ + ((cvc_value.size() > 1) ? " with "+ + cvm::to_str(cvc_value.size())+" individual components.\n" : + ".\n")); + x.type(cvc_value); + x_reported.type(cvc_value); + } + + // If using scripted biases, any colvar may receive bias forces + // and will need its gradient + if (cvm::scripted_forces()) { + enable(task_gradients); + } + // check for linear combinations + + b_linear = !tasks[task_scripted]; + for (i = 0; i < cvcs.size(); i++) { if ((cvcs[i])->b_debug_gradients) - enable (task_gradients); + enable(task_gradients); if ((cvcs[i])->sup_np != 1) { if (cvm::debug() && b_linear) - cvm::log ("Warning: You are using a non-linear polynomial " + cvm::log("Warning: You are using a non-linear polynomial " "combination to define this collective variable, " "some biasing methods may be unavailable.\n"); b_linear = false; if ((cvcs[i])->sup_np < 0) { - cvm::log ("Warning: you chose a negative exponent in the combination; " + cvm::log("Warning: you chose a negative exponent in the combination; " "if you apply forces, the simulation may become unstable " "when the component \""+ (cvcs[i])->function_type+"\" approaches zero.\n"); } } + } + + // Colvar is homogeneous iff: + // - it is not scripted + // - it is linear + // - all cvcs have coefficient 1 or -1 + // i.e. sum or difference of cvcs + + b_homogeneous = !tasks[task_scripted] && b_linear; + for (i = 0; i < cvcs.size(); i++) { + if ((std::fabs(cvcs[i]->sup_coeff) - 1.0) > 1.0e-10) { + b_homogeneous = false; + } + } + + // Colvar is deemed periodic iff: + // - it is homogeneous + // - all cvcs are periodic + // - all cvcs have the same period + + b_periodic = cvcs[0]->b_periodic && b_homogeneous; + period = cvcs[0]->period; + for (i = 1; i < cvcs.size(); i++) { + if (!cvcs[i]->b_periodic || cvcs[i]->period != period) { + b_periodic = false; + period = 0.0; + } + } + + // these will be set to false if any of the cvcs has them false + b_inverse_gradients = !tasks[task_scripted]; + b_Jacobian_force = !tasks[task_scripted]; + // check the available features of each cvc + for (i = 0; i < cvcs.size(); i++) { if ((cvcs[i])->b_periodic && !b_periodic) { - cvm::log ("Warning: although this component is periodic, the colvar will " + cvm::log("Warning: although this component is periodic, the colvar will " "not be treated as periodic, either because the exponent is not " "1, or because multiple components are present. Make sure that " "you know what you are doing!"); } if (! (cvcs[i])->b_inverse_gradients) b_inverse_gradients = false; if (! (cvcs[i])->b_Jacobian_derivative) b_Jacobian_force = false; - if (!tasks[task_scripted]) { - // If the combination of components is a scripted function, - // the components may have different types - for (size_t j = i; j < cvcs.size(); j++) { - if ( (cvcs[i])->type() != (cvcs[j])->type() ) { - cvm::log ("ERROR: you are definining this collective variable " - "by using components of different types, \""+ - colvarvalue::type_desc[(cvcs[i])->type()]+ - "\" and \""+ - colvarvalue::type_desc[(cvcs[j])->type()]+ - "\". " - "You must use the same type in order to " - " sum them together.\n"); - cvm::set_error_bits(INPUT_ERROR); - } - } + // components may have different types only for scripted functions + if (!tasks[task_scripted] && (colvarvalue::check_types(cvcs[i]->value(), + cvcs[0]->value())) ) { + cvm::error("ERROR: you are definining this collective variable " + "by using components of different types. " + "You must use the same type in order to " + " sum them together.\n", INPUT_ERROR); + return; } } - if (!tasks[task_scripted]) { - colvarvalue::Type const value_type = (cvcs[0])->type(); - if (cvm::debug()) - cvm::log ("This collective variable is a "+ - colvarvalue::type_desc[value_type]+", corresponding to "+ - cvm::to_str (colvarvalue::dof_num[value_type])+ - " internal degrees of freedom.\n"); - x.type (value_type); - x_reported.type (value_type); - } - - get_keyval (conf, "width", width, 1.0); + get_keyval(conf, "width", width, 1.0); if (width <= 0.0) { cvm::error("Error: \"width\" must be positive.\n", INPUT_ERROR); } - lower_boundary.type (this->type()); - lower_wall.type (this->type()); + lower_boundary.type(value()); + lower_wall.type(value()); - upper_boundary.type (this->type()); - upper_wall.type (this->type()); + upper_boundary.type(value()); + upper_wall.type(value()); - if (this->type() == colvarvalue::type_scalar) { + if (value().type() == colvarvalue::type_scalar) { - if (get_keyval (conf, "lowerBoundary", lower_boundary, lower_boundary)) { - enable (task_lower_boundary); + if (get_keyval(conf, "lowerBoundary", lower_boundary, lower_boundary)) { + enable(task_lower_boundary); } - get_keyval (conf, "lowerWallConstant", lower_wall_k, 0.0); + get_keyval(conf, "lowerWallConstant", lower_wall_k, 0.0); if (lower_wall_k > 0.0) { - get_keyval (conf, "lowerWall", lower_wall, lower_boundary); - enable (task_lower_wall); + get_keyval(conf, "lowerWall", lower_wall, lower_boundary); + enable(task_lower_wall); } - if (get_keyval (conf, "upperBoundary", upper_boundary, upper_boundary)) { - enable (task_upper_boundary); + if (get_keyval(conf, "upperBoundary", upper_boundary, upper_boundary)) { + enable(task_upper_boundary); } - get_keyval (conf, "upperWallConstant", upper_wall_k, 0.0); + get_keyval(conf, "upperWallConstant", upper_wall_k, 0.0); if (upper_wall_k > 0.0) { - get_keyval (conf, "upperWall", upper_wall, upper_boundary); - enable (task_upper_wall); + get_keyval(conf, "upperWall", upper_wall, upper_boundary); + enable(task_upper_wall); } } if (tasks[task_lower_boundary]) { - get_keyval (conf, "hardLowerBoundary", hard_lower_boundary, false); + get_keyval(conf, "hardLowerBoundary", hard_lower_boundary, false); } if (tasks[task_upper_boundary]) { - get_keyval (conf, "hardUpperBoundary", hard_upper_boundary, false); + get_keyval(conf, "hardUpperBoundary", hard_upper_boundary, false); } // consistency checks for boundaries and walls if (tasks[task_lower_boundary] && tasks[task_upper_boundary]) { if (lower_boundary >= upper_boundary) { - cvm::error ("Error: the upper boundary, "+ - cvm::to_str (upper_boundary)+ + cvm::error("Error: the upper boundary, "+ + cvm::to_str(upper_boundary)+ ", is not higher than the lower boundary, "+ - cvm::to_str (lower_boundary)+".\n", + cvm::to_str(lower_boundary)+".\n", INPUT_ERROR); } } if (tasks[task_lower_wall] && tasks[task_upper_wall]) { if (lower_wall >= upper_wall) { - cvm::error ("Error: the upper wall, "+ - cvm::to_str (upper_wall)+ + cvm::error("Error: the upper wall, "+ + cvm::to_str(upper_wall)+ ", is not higher than the lower wall, "+ - cvm::to_str (lower_wall)+".\n", + cvm::to_str(lower_wall)+".\n", INPUT_ERROR); } - if (dist2 (lower_wall, upper_wall) < 1.0E-12) { - cvm::log ("Lower wall and upper wall are equal " + if (dist2(lower_wall, upper_wall) < 1.0E-12) { + cvm::log("Lower wall and upper wall are equal " "in the periodic domain of the colvar: disabling walls.\n"); - disable (task_lower_wall); - disable (task_upper_wall); + disable(task_lower_wall); + disable(task_upper_wall); } } - get_keyval (conf, "expandBoundaries", expand_boundaries, false); + get_keyval(conf, "expandBoundaries", expand_boundaries, false); if (expand_boundaries && periodic_boundaries()) { - cvm::error ("Error: trying to expand boundaries that already " + cvm::error("Error: trying to expand boundaries that already " "cover a whole period of a periodic colvar.\n", INPUT_ERROR); } if (expand_boundaries && hard_lower_boundary && hard_upper_boundary) { - cvm::error ("Error: inconsistent configuration " + cvm::error("Error: inconsistent configuration " "(trying to expand boundaries with both " "hardLowerBoundary and hardUpperBoundary enabled).\n", INPUT_ERROR); } { bool b_extended_lagrangian; - get_keyval (conf, "extendedLagrangian", b_extended_lagrangian, false); + get_keyval(conf, "extendedLagrangian", b_extended_lagrangian, false); if (b_extended_lagrangian) { cvm::real temp, tolerance, period; - cvm::log ("Enabling the extended Lagrangian term for colvar \""+ + cvm::log("Enabling the extended Lagrangian term for colvar \""+ this->name+"\".\n"); - enable (task_extended_lagrangian); + enable(task_extended_lagrangian); - xr.type (this->type()); - vr.type (this->type()); - fr.type (this->type()); + xr.type(value()); + vr.type(value()); + fr.type(value()); - const bool found = get_keyval (conf, "extendedTemp", temp, cvm::temperature()); + const bool found = get_keyval(conf, "extendedTemp", temp, cvm::temperature()); if (temp <= 0.0) { if (found) - cvm::log ("Error: \"extendedTemp\" must be positive.\n"); + cvm::error("Error: \"extendedTemp\" must be positive.\n", INPUT_ERROR); else - cvm::error ("Error: a positive temperature must be provided, either " - "by enabling a thermostat, or through \"extendedTemp\".\n", - INPUT_ERROR); + cvm::error("Error: a positive temperature must be provided, either " + "by enabling a thermostat, or through \"extendedTemp\".\n", + INPUT_ERROR); } - get_keyval (conf, "extendedFluctuation", tolerance); + get_keyval(conf, "extendedFluctuation", tolerance); if (tolerance <= 0.0) { cvm::error("Error: \"extendedFluctuation\" must be positive.\n", INPUT_ERROR); } ext_force_k = cvm::boltzmann() * temp / (tolerance * tolerance); - cvm::log ("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " kcal/mol/U^2"); + cvm::log("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " kcal/mol/U^2"); - get_keyval (conf, "extendedTimeConstant", period, 200.0); + get_keyval(conf, "extendedTimeConstant", period, 200.0); if (period <= 0.0) { cvm::error("Error: \"extendedTimeConstant\" must be positive.\n", INPUT_ERROR); } ext_mass = (cvm::boltzmann() * temp * period * period) / (4.0 * PI * PI * tolerance * tolerance); - cvm::log ("Computed fictitious mass: " + cvm::to_str(ext_mass) + " kcal/mol/(U/fs)^2 (U: colvar unit)"); + cvm::log("Computed fictitious mass: " + cvm::to_str(ext_mass) + " kcal/mol/(U/fs)^2 (U: colvar unit)"); { bool b_output_energy; - get_keyval (conf, "outputEnergy", b_output_energy, false); + get_keyval(conf, "outputEnergy", b_output_energy, false); if (b_output_energy) { - enable (task_output_energy); + enable(task_output_energy); } } - get_keyval (conf, "extendedLangevinDamping", ext_gamma, 1.0); + get_keyval(conf, "extendedLangevinDamping", ext_gamma, 1.0); if (ext_gamma < 0.0) { cvm::error("Error: \"extendedLangevinDamping\" may not be negative.\n", INPUT_ERROR); } if (ext_gamma != 0.0) { - enable (task_langevin); + enable(task_langevin); ext_gamma *= 1.0e-3; // convert from ps-1 to fs-1 ext_sigma = std::sqrt(2.0 * cvm::boltzmann() * temp * ext_gamma * ext_mass / cvm::dt()); } } } { bool b_output_value; - get_keyval (conf, "outputValue", b_output_value, true); + get_keyval(conf, "outputValue", b_output_value, true); if (b_output_value) { - enable (task_output_value); + enable(task_output_value); } } { bool b_output_velocity; - get_keyval (conf, "outputVelocity", b_output_velocity, false); + get_keyval(conf, "outputVelocity", b_output_velocity, false); if (b_output_velocity) { - enable (task_output_velocity); + enable(task_output_velocity); } } { bool b_output_system_force; - get_keyval (conf, "outputSystemForce", b_output_system_force, false); + get_keyval(conf, "outputSystemForce", b_output_system_force, false); if (b_output_system_force) { - enable (task_output_system_force); + enable(task_output_system_force); } } { bool b_output_applied_force; - get_keyval (conf, "outputAppliedForce", b_output_applied_force, false); + get_keyval(conf, "outputAppliedForce", b_output_applied_force, false); if (b_output_applied_force) { - enable (task_output_applied_force); + enable(task_output_applied_force); } } if (cvm::b_analysis) - parse_analysis (conf); + parse_analysis(conf); if (cvm::debug()) - cvm::log ("Done initializing collective variable \""+this->name+"\".\n"); + cvm::log("Done initializing collective variable \""+this->name+"\".\n"); } -void colvar::build_atom_list (void) +void colvar::build_atom_list(void) { // If atomic gradients are requested, build full list of atom ids from all cvcs std::list temp_id_list; for (size_t i = 0; i < cvcs.size(); i++) { for (size_t j = 0; j < cvcs[i]->atom_groups.size(); j++) { for (size_t k = 0; k < cvcs[i]->atom_groups[j]->size(); k++) { - temp_id_list.push_back (cvcs[i]->atom_groups[j]->at(k).id); + temp_id_list.push_back(cvcs[i]->atom_groups[j]->at(k).id); } } } temp_id_list.sort(); temp_id_list.unique(); // atom_ids = std::vector (temp_id_list.begin(), temp_id_list.end()); unsigned int id_i = 0; std::list::iterator li; for (li = temp_id_list.begin(); li != temp_id_list.end(); ++li) { atom_ids[id_i] = *li; id_i++; } temp_id_list.clear(); - atomic_gradients.resize (atom_ids.size()); + atomic_gradients.resize(atom_ids.size()); if (atom_ids.size()) { if (cvm::debug()) - cvm::log ("Colvar: created atom list with " + cvm::to_str(atom_ids.size()) + " atoms.\n"); + cvm::log("Colvar: created atom list with " + cvm::to_str(atom_ids.size()) + " atoms.\n"); } else { - cvm::log ("Warning: colvar components communicated no atom IDs.\n"); + cvm::log("Warning: colvar components communicated no atom IDs.\n"); } } -int colvar::parse_analysis (std::string const &conf) +int colvar::parse_analysis(std::string const &conf) { // if (cvm::debug()) // cvm::log ("Parsing analysis flags for collective variable \""+ // this->name+"\".\n"); runave_length = 0; bool b_runave = false; - if (get_keyval (conf, "runAve", b_runave) && b_runave) { + if (get_keyval(conf, "runAve", b_runave) && b_runave) { - enable (task_runave); + enable(task_runave); - get_keyval (conf, "runAveLength", runave_length, 1000); - get_keyval (conf, "runAveStride", runave_stride, 1); + get_keyval(conf, "runAveLength", runave_length, 1000); + get_keyval(conf, "runAveStride", runave_stride, 1); if ((cvm::restart_out_freq % runave_stride) != 0) { cvm::error("Error: runAveStride must be commensurate with the restart frequency.\n", INPUT_ERROR); } std::string runave_outfile; - get_keyval (conf, "runAveOutputFile", runave_outfile, - std::string (cvm::output_prefix+"."+ + 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); - runave_os.open (runave_outfile.c_str()); - runave_os << "# " << cvm::wrap_string ("step", cvm::it_width-2) + size_t const this_cv_width = x.output_width(cvm::cv_width); + runave_os.open(runave_outfile.c_str()); + runave_os << "# " << cvm::wrap_string("step", cvm::it_width-2) << " " - << cvm::wrap_string ("running average", this_cv_width) + << cvm::wrap_string("running average", this_cv_width) << " " - << cvm::wrap_string ("running stddev", this_cv_width) + << cvm::wrap_string("running stddev", this_cv_width) << "\n"; } acf_length = 0; bool b_acf = false; - if (get_keyval (conf, "corrFunc", b_acf) && b_acf) { + if (get_keyval(conf, "corrFunc", b_acf) && b_acf) { - enable (task_corrfunc); + enable(task_corrfunc); std::string acf_colvar_name; - get_keyval (conf, "corrFuncWithColvar", acf_colvar_name, this->name); + get_keyval(conf, "corrFuncWithColvar", acf_colvar_name, this->name); if (acf_colvar_name == this->name) { - cvm::log ("Calculating auto-correlation function.\n"); + cvm::log("Calculating auto-correlation function.\n"); } else { - cvm::log ("Calculating correlation function with \""+ + cvm::log("Calculating correlation function with \""+ this->name+"\".\n"); } std::string acf_type_str; - get_keyval (conf, "corrFuncType", acf_type_str, to_lower_cppstr (std::string ("velocity"))); - if (acf_type_str == to_lower_cppstr (std::string ("coordinate"))) { + get_keyval(conf, "corrFuncType", acf_type_str, to_lower_cppstr(std::string("velocity"))); + if (acf_type_str == to_lower_cppstr(std::string("coordinate"))) { acf_type = acf_coor; - } else if (acf_type_str == to_lower_cppstr (std::string ("velocity"))) { + } else if (acf_type_str == to_lower_cppstr(std::string("velocity"))) { acf_type = acf_vel; - enable (task_fdiff_velocity); + enable(task_fdiff_velocity); if (acf_colvar_name.size()) - (cvm::colvar_by_name (acf_colvar_name))->enable (task_fdiff_velocity); - } else if (acf_type_str == to_lower_cppstr (std::string ("coordinate_p2"))) { + (cvm::colvar_by_name(acf_colvar_name))->enable(task_fdiff_velocity); + } else if (acf_type_str == to_lower_cppstr(std::string("coordinate_p2"))) { acf_type = acf_p2coor; } else { - cvm::log ("Unknown type of correlation function, \""+ + cvm::log("Unknown type of correlation function, \""+ acf_type_str+"\".\n"); cvm::set_error_bits(INPUT_ERROR); } - get_keyval (conf, "corrFuncOffset", acf_offset, 0); - get_keyval (conf, "corrFuncLength", acf_length, 1000); - get_keyval (conf, "corrFuncStride", acf_stride, 1); + get_keyval(conf, "corrFuncOffset", acf_offset, 0); + get_keyval(conf, "corrFuncLength", acf_length, 1000); + get_keyval(conf, "corrFuncStride", acf_stride, 1); if ((cvm::restart_out_freq % acf_stride) != 0) { cvm::error("Error: corrFuncStride must be commensurate with the restart frequency.\n", INPUT_ERROR); } - get_keyval (conf, "corrFuncNormalize", acf_normalize, true); - get_keyval (conf, "corrFuncOutputFile", acf_outfile, - std::string (cvm::output_prefix+"."+this->name+ + get_keyval(conf, "corrFuncNormalize", acf_normalize, true); + get_keyval(conf, "corrFuncOutputFile", acf_outfile, + std::string(cvm::output_prefix+"."+this->name+ ".corrfunc.dat")); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -int colvar::enable (colvar::task const &t) +int colvar::enable(colvar::task const &t) { switch (t) { case task_output_system_force: - enable (task_system_force); + enable(task_system_force); break; case task_report_Jacobian_force: - enable (task_Jacobian_force); - enable (task_system_force); + enable(task_Jacobian_force); + enable(task_system_force); if (cvm::debug()) - cvm::log ("Adding the Jacobian force to the system force, " + cvm::log("Adding the Jacobian force to the system force, " "rather than applying its opposite silently.\n"); break; case task_Jacobian_force: // checks below do not apply to extended-system colvars if ( !tasks[task_extended_lagrangian] ) { - enable (task_gradients); + enable(task_gradients); if (!b_Jacobian_force) { - cvm::error ("Error: colvar \""+this->name+ + cvm::error("Error: colvar \""+this->name+ "\" does not have Jacobian forces implemented.\n", INPUT_ERROR); } if (!b_linear) { - cvm::error ("Error: colvar \""+this->name+ + cvm::error("Error: colvar \""+this->name+ "\" must be defined as a linear combination " "to calculate the Jacobian force.\n", INPUT_ERROR); } if (cvm::debug()) - cvm::log ("Enabling calculation of the Jacobian force " + cvm::log("Enabling calculation of the Jacobian force " "on this colvar.\n"); } - fj.type (this->type()); + fj.type(value()); break; case task_system_force: if (!tasks[task_extended_lagrangian]) { if (!b_inverse_gradients) { - cvm::error ("Error: one or more of the components of " + cvm::error("Error: one or more of the components of " "colvar \""+this->name+ "\" does not support system force calculation.\n", INPUT_ERROR); } cvm::request_system_force(); } - ft.type (this->type()); - ft_reported.type (this->type()); + ft.type(value()); + ft_reported.type(value()); break; case task_output_applied_force: case task_lower_wall: case task_upper_wall: // all of the above require gradients - enable (task_gradients); + enable(task_gradients); break; case task_fdiff_velocity: - x_old.type (this->type()); - v_fdiff.type (this->type()); - v_reported.type (this->type()); + x_old.type(value()); + v_fdiff.type(value()); + v_reported.type(value()); break; case task_output_velocity: - enable (task_fdiff_velocity); + enable(task_fdiff_velocity); break; case task_grid: - if (this->type() != colvarvalue::type_scalar) { - cvm::error ("Cannot calculate a grid for collective variable, \""+ + if (value().type() != colvarvalue::type_scalar) { + cvm::error("Cannot calculate a grid for collective variable, \""+ this->name+"\", because its value is not a scalar number.\n", INPUT_ERROR); } break; case task_extended_lagrangian: - enable (task_gradients); - v_reported.type (this->type()); + enable(task_gradients); + v_reported.type(value()); break; case task_lower_boundary: case task_upper_boundary: - if (this->type() != colvarvalue::type_scalar) { - cvm::error ("Error: this colvar is not a scalar value " + if (value().type() != colvarvalue::type_scalar) { + cvm::error("Error: this colvar is not a scalar value " "and cannot produce a grid.\n", INPUT_ERROR); } break; case task_output_value: case task_runave: case task_corrfunc: case task_ntot: case task_langevin: case task_output_energy: case task_scripted: break; case task_gradients: - f.type (this->type()); - fb.type (this->type()); + f.type(value()); + fb.type(value()); break; case task_collect_gradients: - if (this->type() != colvarvalue::type_scalar) { - cvm::error ("Collecting atomic gradients for non-scalar collective variable \""+ + if (value().type() != colvarvalue::type_scalar) { + cvm::error("Collecting atomic gradients for non-scalar collective variable \""+ this->name+"\" is not yet implemented.\n", INPUT_ERROR); } - enable (task_gradients); + enable(task_gradients); if (atom_ids.size() == 0) { build_atom_list(); } break; } tasks[t] = true; return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -void colvar::disable (colvar::task const &t) +void colvar::disable(colvar::task const &t) { // check dependencies switch (t) { case task_gradients: - disable (task_upper_wall); - disable (task_lower_wall); - disable (task_output_applied_force); - disable (task_system_force); - disable (task_Jacobian_force); + disable(task_upper_wall); + disable(task_lower_wall); + disable(task_output_applied_force); + disable(task_system_force); + disable(task_Jacobian_force); break; case task_system_force: - disable (task_output_system_force); + disable(task_output_system_force); break; case task_Jacobian_force: - disable (task_report_Jacobian_force); + disable(task_report_Jacobian_force); break; case task_fdiff_velocity: - disable (task_output_velocity); + disable(task_output_velocity); break; case task_lower_boundary: case task_upper_boundary: - disable (task_grid); + disable(task_grid); break; case task_extended_lagrangian: case task_report_Jacobian_force: case task_output_value: case task_output_velocity: case task_output_applied_force: case task_output_system_force: case task_runave: case task_corrfunc: case task_grid: case task_lower_wall: case task_upper_wall: case task_ntot: case task_langevin: case task_output_energy: case task_collect_gradients: case task_scripted: break; } tasks[t] = false; } void colvar::setup() { // loop over all components to reset masses of all groups for (size_t i = 0; i < cvcs.size(); i++) { for (size_t ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) { cvm::atom_group &atoms = *(cvcs[i]->atom_groups[ig]); atoms.read_positions(); atoms.reset_mass(name,i,ig); } } } colvar::~colvar() { for (size_t i = 0; i < cvcs.size(); i++) { delete cvcs[i]; } // remove reference to this colvar from the CVM for (std::vector::iterator cvi = cvm::colvars.begin(); cvi != cvm::colvars.end(); ++cvi) { if ( *cvi == this) { - cvm::colvars.erase (cvi); + cvm::colvars.erase(cvi); break; } } } // ******************** CALC FUNCTIONS ******************** void colvar::calc() { size_t i, ig; if (cvm::debug()) - cvm::log ("Calculating colvar \""+this->name+"\".\n"); + cvm::log("Calculating colvar \""+this->name+"\".\n"); // prepare atom groups for calculation if (cvm::debug()) - cvm::log ("Collecting data from atom groups.\n"); + cvm::log("Collecting data from atom groups.\n"); for (i = 0; i < cvcs.size(); i++) { for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) { cvm::atom_group &atoms = *(cvcs[i]->atom_groups[ig]); atoms.reset_atoms_data(); atoms.read_positions(); if (atoms.b_center || atoms.b_rotate) { atoms.calc_apply_roto_translation(); } // each atom group will take care of its own ref_pos_group, if defined } } //// 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++) { cvcs[i]->atom_groups[ig]->read_system_forces(); } } } // calculate the value of the colvar if (cvm::debug()) - cvm::log ("Calculating colvar components.\n"); + cvm::log("Calculating colvar components.\n"); x.reset(); // First, update component values for (i = 0; i < cvcs.size(); i++) { cvm::increase_depth(); (cvcs[i])->calc_value(); cvm::decrease_depth(); if (cvm::debug()) - cvm::log ("Colvar component no. "+cvm::to_str (i+1)+ + cvm::log("Colvar component no. "+cvm::to_str(i+1)+ " within colvar \""+this->name+"\" has value "+ - cvm::to_str ((cvcs[i])->value(), + cvm::to_str((cvcs[i])->value(), cvm::cv_width, cvm::cv_prec)+".\n"); } // Then combine them appropriately if (tasks[task_scripted]) { // cvcs combined by user script int res = cvm::proxy->run_colvar_callback(scripted_function, sorted_cvc_values, x); if (res == COLVARS_NOT_IMPLEMENTED) { cvm::error("Scripted colvars are not implemented."); return; } if (res != COLVARS_OK) { cvm::error("Error running scripted colvar"); return; } } else if (x.type() == colvarvalue::type_scalar) { // polynomial combination allowed for (i = 0; i < cvcs.size(); i++) { x += (cvcs[i])->sup_coeff * ( ((cvcs[i])->sup_np != 1) ? - std::pow ((cvcs[i])->value().real_value, (cvcs[i])->sup_np) : + std::pow((cvcs[i])->value().real_value, (cvcs[i])->sup_np) : (cvcs[i])->value().real_value ); } } else { // only linear combination allowed for (i = 0; i < cvcs.size(); i++) { x += (cvcs[i])->sup_coeff * (cvcs[i])->value(); } } if (cvm::debug()) - cvm::log ("Colvar \""+this->name+"\" has value "+ - cvm::to_str (x, cvm::cv_width, cvm::cv_prec)+".\n"); + cvm::log("Colvar \""+this->name+"\" has value "+ + cvm::to_str(x, cvm::cv_width, cvm::cv_prec)+".\n"); if (tasks[task_gradients]) { if (cvm::debug()) - cvm::log ("Calculating gradients of colvar \""+this->name+"\".\n"); + cvm::log("Calculating gradients of colvar \""+this->name+"\".\n"); for (i = 0; i < cvcs.size(); i++) { // calculate the gradients of each component cvm::increase_depth(); (cvcs[i])->calc_gradients(); // if requested, propagate (via chain rule) the gradients above // to the atoms used to define the roto-translation for (ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) { if (cvcs[i]->atom_groups[ig]->b_fit_gradients) cvcs[i]->atom_groups[ig]->calc_fit_gradients(); } cvm::decrease_depth(); } if (cvm::debug()) - cvm::log ("Done calculating gradients of colvar \""+this->name+"\".\n"); + cvm::log("Done calculating gradients of colvar \""+this->name+"\".\n"); if (tasks[task_collect_gradients]) { if (tasks[task_scripted]) { cvm::error("Collecting atomic gradients is not implemented for " "scripted colvars."); return; } // Collect the atomic gradients inside colvar object for (unsigned int a = 0; a < atomic_gradients.size(); a++) { atomic_gradients[a].reset(); } for (i = 0; i < cvcs.size(); i++) { // Coefficient: d(a * x^n) = a * n * x^(n-1) * dx - cvm::real coeff = (cvcs[i])->sup_coeff * cvm::real ((cvcs[i])->sup_np) * - std::pow ((cvcs[i])->value().real_value, (cvcs[i])->sup_np-1); + cvm::real coeff = (cvcs[i])->sup_coeff * cvm::real((cvcs[i])->sup_np) * + std::pow((cvcs[i])->value().real_value, (cvcs[i])->sup_np-1); for (size_t j = 0; j < cvcs[i]->atom_groups.size(); j++) { // If necessary, apply inverse rotation to get atomic // gradient in the laboratory frame if (cvcs[i]->atom_groups[j]->b_rotate) { cvm::rotation const rot_inv = cvcs[i]->atom_groups[j]->rot.inverse(); for (size_t k = 0; k < cvcs[i]->atom_groups[j]->size(); k++) { - int a = std::lower_bound (atom_ids.begin(), atom_ids.end(), + int a = std::lower_bound(atom_ids.begin(), atom_ids.end(), cvcs[i]->atom_groups[j]->at(k).id) - atom_ids.begin(); atomic_gradients[a] += coeff * - rot_inv.rotate (cvcs[i]->atom_groups[j]->at(k).grad); + rot_inv.rotate(cvcs[i]->atom_groups[j]->at(k).grad); } } else { for (size_t k = 0; k < cvcs[i]->atom_groups[j]->size(); k++) { - int a = std::lower_bound (atom_ids.begin(), atom_ids.end(), + int a = std::lower_bound(atom_ids.begin(), atom_ids.end(), cvcs[i]->atom_groups[j]->at(k).id) - atom_ids.begin(); atomic_gradients[a] += coeff * cvcs[i]->atom_groups[j]->at(k).grad; } } } } } } if (tasks[task_system_force]) { if (tasks[task_scripted]) { // TODO see if this could reasonably be done in a generic way // from generic inverse gradients cvm::error("System force is not implemented for " "scripted colvars."); return; } if (cvm::debug()) - cvm::log ("Calculating system force of colvar \""+this->name+"\".\n"); + cvm::log("Calculating system force of colvar \""+this->name+"\".\n"); ft.reset(); - // if(!tasks[task_extended_lagrangian] && (cvm::step_relative() > 0)) { + // if (!tasks[task_extended_lagrangian] && (cvm::step_relative() > 0)) { // Disabled check to allow for explicit system force calculation // even with extended Lagrangian - if(cvm::step_relative() > 0) { + if (cvm::step_relative() > 0) { // get from the cvcs the system forces from the PREVIOUS step for (i = 0; i < cvcs.size(); i++) { (cvcs[i])->calc_force_invgrads(); // linear combination is assumed cvm::increase_depth(); - ft += (cvcs[i])->system_force() / ((cvcs[i])->sup_coeff * cvm::real (cvcs.size())); + ft += (cvcs[i])->system_force() / ((cvcs[i])->sup_coeff * cvm::real(cvcs.size())); cvm::decrease_depth(); } } if (tasks[task_report_Jacobian_force]) { // add the Jacobian force to the system force, and don't apply any silent // correction internally: biases such as colvarbias_abf will handle it ft += fj; } if (cvm::debug()) - cvm::log ("Done calculating system force of colvar \""+this->name+"\".\n"); + cvm::log("Done calculating system force of colvar \""+this->name+"\".\n"); } if (tasks[task_fdiff_velocity]) { // calculate the velocity by finite differences if (cvm::step_relative() == 0) x_old = x; else { - v_fdiff = fdiff_velocity (x_old, x); + v_fdiff = fdiff_velocity(x_old, x); v_reported = v_fdiff; } } if (tasks[task_extended_lagrangian]) { // initialize the restraint center in the first step to the value // just calculated from the cvcs // TODO: put it in the restart information if (cvm::step_relative() == 0) { xr = x; vr = 0.0; // (already 0; added for clarity) } // report the restraint center as "value" x_reported = xr; v_reported = vr; // the "system force" with the extended Lagrangian is just the // harmonic term acting on the extended coordinate // Note: this is the force for current timestep - ft_reported = (-0.5 * ext_force_k) * this->dist2_lgrad (xr, x); + ft_reported = (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x); } else { x_reported = x; ft_reported = ft; } if (cvm::debug()) - cvm::log ("Done calculating colvar \""+this->name+"\".\n"); + cvm::log("Done calculating colvar \""+this->name+"\".\n"); } cvm::real colvar::update() { if (cvm::debug()) - cvm::log ("Updating colvar \""+this->name+"\".\n"); - + cvm::log("Updating colvar \""+this->name+"\".\n"); // set to zero the applied force + f.type(value()); f.reset(); // add the biases' force, which at this point should already have // been summed over each bias using this colvar f += fb; if (tasks[task_lower_wall] || tasks[task_upper_wall]) { // wall force - colvarvalue fw (this->type()); + colvarvalue fw(value()); + fw.reset(); + + if (cvm::debug()) + cvm::log("Calculating wall forces for colvar \""+this->name+"\".\n"); // if the two walls are applied concurrently, decide which is the // closer one (on a periodic colvar, both walls may be applicable // at the same time) if ( (!tasks[task_upper_wall]) || - (this->dist2 (x, lower_wall) < this->dist2 (x, upper_wall)) ) { + (this->dist2(x, lower_wall) < this->dist2(x, upper_wall)) ) { - cvm::real const grad = this->dist2_lgrad (x, lower_wall); + cvm::real const grad = this->dist2_lgrad(x, lower_wall); if (grad < 0.0) { fw = -0.5 * lower_wall_k * grad; if (cvm::debug()) - cvm::log ("Applying a lower wall force ("+ - cvm::to_str (fw)+") to \""+this->name+"\".\n"); + cvm::log("Applying a lower wall force("+ + cvm::to_str(fw)+") to \""+this->name+"\".\n"); f += fw; } } else { - cvm::real const grad = this->dist2_lgrad (x, upper_wall); + cvm::real const grad = this->dist2_lgrad(x, upper_wall); if (grad > 0.0) { fw = -0.5 * upper_wall_k * grad; if (cvm::debug()) - cvm::log ("Applying an upper wall force ("+ - cvm::to_str (fw)+") to \""+this->name+"\".\n"); + cvm::log("Applying an upper wall force("+ + cvm::to_str(fw)+") to \""+this->name+"\".\n"); f += fw; } } } if (tasks[task_Jacobian_force]) { size_t i; cvm::increase_depth(); for (i = 0; i < cvcs.size(); i++) { (cvcs[i])->calc_Jacobian_derivative(); } cvm::decrease_depth(); fj.reset(); for (i = 0; i < cvcs.size(); i++) { // linear combination is assumed - fj += 1.0 / ( cvm::real (cvcs.size()) * cvm::real ((cvcs[i])->sup_coeff) ) * + fj += 1.0 / ( cvm::real(cvcs.size()) * cvm::real((cvcs[i])->sup_coeff) ) * (cvcs[i])->Jacobian_derivative(); } fj *= cvm::boltzmann() * cvm::temperature(); // the instantaneous Jacobian force was not included in the reported system force; // instead, it is subtracted from the applied force (silent Jacobian correction) if (! tasks[task_report_Jacobian_force]) f -= fj; } if (tasks[task_extended_lagrangian]) { cvm::real dt = cvm::dt(); cvm::real f_ext; // the total force is applied to the fictitious mass, while the // atoms only feel the harmonic force // fr: extended coordinate force (without harmonic spring), for output in trajectory // f_ext: total force on extended coordinate (including harmonic spring) // f: - initially, external biasing force // - after this code block, colvar force to be applied to atomic coordinates, ie. spring force fr = f; - f_ext = f + (-0.5 * ext_force_k) * this->dist2_lgrad (xr, x); - f = (-0.5 * ext_force_k) * this->dist2_rgrad (xr, x); + f_ext = f + (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x); + f = (-0.5 * ext_force_k) * this->dist2_rgrad(xr, x); // leapfrog: starting from x_i, f_i, v_(i-1/2) vr += (0.5 * dt) * f_ext / ext_mass; // Because of leapfrog, kinetic energy at time i is approximate kinetic_energy = 0.5 * ext_mass * vr * vr; potential_energy = 0.5 * ext_force_k * this->dist2(xr, x); // leap to v_(i+1/2) if (tasks[task_langevin]) { vr -= dt * ext_gamma * vr.real_value; vr += dt * ext_sigma * cvm::rand_gaussian() / ext_mass; } vr += (0.5 * dt) * f_ext / ext_mass; xr += dt * vr; xr.apply_constraints(); - if (this->b_periodic) this->wrap (xr); + if (this->b_periodic) this->wrap(xr); } if (tasks[task_fdiff_velocity]) { // set it for the next step x_old = x; } if (cvm::debug()) - cvm::log ("Done updating colvar \""+this->name+"\".\n"); + cvm::log("Done updating colvar \""+this->name+"\".\n"); return (potential_energy + kinetic_energy); } void colvar::communicate_forces() { size_t i; if (cvm::debug()) - cvm::log ("Communicating forces from colvar \""+this->name+"\".\n"); + cvm::log("Communicating forces from colvar \""+this->name+"\".\n"); if (tasks[task_scripted]) { - std::vector func_grads(cvcs.size()); + std::vector > func_grads; + for (i = 0; i < cvcs.size(); i++) { + func_grads.push_back(cvm::matrix2d (x.size(), + cvcs[i]->value().size())); + } int res = cvm::proxy->run_colvar_gradient_callback(scripted_function, sorted_cvc_values, func_grads); - if (res == COLVARS_NOT_IMPLEMENTED) { - cvm::error("Colvar gradient scripts are not implemented."); - return; - } if (res != COLVARS_OK) { - cvm::error("Error running colvar gradient script"); + if (res == COLVARS_NOT_IMPLEMENTED) { + cvm::error("Colvar gradient scripts are not implemented."); + } else { + cvm::error("Error running colvar gradient script"); + } return; } for (i = 0; i < cvcs.size(); i++) { cvm::increase_depth(); - // 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]); + // cvc force is colvar force times colvar/cvc Jacobian + // (vector-matrix product) + (cvcs[i])->apply_force(colvarvalue(f.as_vector() * func_grads[i], + cvcs[i]->value().type())); cvm::decrease_depth(); } } else if (x.type() == colvarvalue::type_scalar) { for (i = 0; i < cvcs.size(); i++) { cvm::increase_depth(); - (cvcs[i])->apply_force (f * (cvcs[i])->sup_coeff * - cvm::real ((cvcs[i])->sup_np) * - (std::pow ((cvcs[i])->value().real_value, + (cvcs[i])->apply_force(f * (cvcs[i])->sup_coeff * + cvm::real((cvcs[i])->sup_np) * + (std::pow((cvcs[i])->value().real_value, (cvcs[i])->sup_np-1)) ); cvm::decrease_depth(); } } else { for (i = 0; i < cvcs.size(); i++) { cvm::increase_depth(); - (cvcs[i])->apply_force (f * (cvcs[i])->sup_coeff); + (cvcs[i])->apply_force(f * (cvcs[i])->sup_coeff); cvm::decrease_depth(); } } if (cvm::debug()) - cvm::log ("Done communicating forces from colvar \""+this->name+"\".\n"); + cvm::log("Done communicating forces from colvar \""+this->name+"\".\n"); } // ******************** METRIC FUNCTIONS ******************** // Use the metrics defined by \link cvc \endlink objects -bool colvar::periodic_boundaries (colvarvalue const &lb, colvarvalue const &ub) const +bool colvar::periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) const { if ( (!tasks[task_lower_boundary]) || (!tasks[task_upper_boundary]) ) { - cvm::log ("Error: requesting to histogram the " + cvm::log("Error: requesting to histogram the " "collective variable \""+this->name+"\", but a " "pair of lower and upper boundaries must be " "defined.\n"); cvm::set_error_bits(INPUT_ERROR); } if (period > 0.0) { - if ( ((std::sqrt (this->dist2 (lb, ub))) / this->width) + if ( ((std::sqrt(this->dist2(lb, ub))) / this->width) < 1.0E-10 ) { return true; } } return false; } bool colvar::periodic_boundaries() const { if ( (!tasks[task_lower_boundary]) || (!tasks[task_upper_boundary]) ) { - cvm::error ("Error: requesting to histogram the " + cvm::error("Error: requesting to histogram the " "collective variable \""+this->name+"\", but a " "pair of lower and upper boundaries must be " "defined.\n"); } - return periodic_boundaries (lower_boundary, upper_boundary); + return periodic_boundaries(lower_boundary, upper_boundary); } -cvm::real colvar::dist2 (colvarvalue const &x1, +cvm::real colvar::dist2(colvarvalue const &x1, colvarvalue const &x2) const { - if (b_single_cvc) { + if (b_homogeneous) { return (cvcs[0])->dist2(x1, x2); } else { return x1.dist2(x2); } } -colvarvalue colvar::dist2_lgrad (colvarvalue const &x1, +colvarvalue colvar::dist2_lgrad(colvarvalue const &x1, colvarvalue const &x2) const { - if (b_single_cvc) { - return (cvcs[0])->dist2_lgrad (x1, x2); + if (b_homogeneous) { + return (cvcs[0])->dist2_lgrad(x1, x2); } else { return x1.dist2_grad(x2); } } -colvarvalue colvar::dist2_rgrad (colvarvalue const &x1, +colvarvalue colvar::dist2_rgrad(colvarvalue const &x1, colvarvalue const &x2) const { - if (b_single_cvc) { - return (cvcs[0])->dist2_rgrad (x1, x2); + if (b_homogeneous) { + return (cvcs[0])->dist2_rgrad(x1, x2); } else { return x2.dist2_grad(x1); } } -void colvar::wrap (colvarvalue &x) const +void colvar::wrap(colvarvalue &x) const { - if (b_single_cvc) { - (cvcs[0])->wrap (x); + if (b_homogeneous) { + (cvcs[0])->wrap(x); } return; } // ******************** INPUT FUNCTIONS ******************** -std::istream & colvar::read_restart (std::istream &is) +std::istream & colvar::read_restart(std::istream &is) { size_t const start_pos = is.tellg(); std::string conf; - if ( !(is >> colvarparse::read_block ("colvar", conf)) ) { + if ( !(is >> colvarparse::read_block("colvar", conf)) ) { // this is not a colvar block is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } { std::string check_name = ""; - if ( (get_keyval (conf, "name", check_name, - std::string (""), colvarparse::parse_silent)) && + if ( (get_keyval(conf, "name", check_name, + std::string(""), colvarparse::parse_silent)) && (check_name != name) ) { - cvm::error ("Error: the state file does not match the " - "configuration file, at colvar \""+name+"\".\n"); + cvm::error("Error: the state file does not match the " + "configuration file, at colvar \""+name+"\".\n"); } if (check_name.size() == 0) { - cvm::error ("Error: Collective variable in the " - "restart file without any identifier.\n"); + cvm::error("Error: Collective variable in the " + "restart file without any identifier.\n"); } } - if ( !(get_keyval (conf, "x", x, - colvarvalue (x.type()), colvarparse::parse_silent)) ) { - cvm::log ("Error: restart file does not contain " - "the value of the colvar \""+ - name+"\" .\n"); + if ( !(get_keyval(conf, "x", x, + colvarvalue(x.type()), colvarparse::parse_silent)) ) { + cvm::log("Error: restart file does not contain " + "the value of the colvar \""+ + name+"\" .\n"); } else { - cvm::log ("Restarting collective variable \""+name+"\" from value: "+ - cvm::to_str (x)+"\n"); + cvm::log("Restarting collective variable \""+name+"\" from value: "+ + cvm::to_str(x)+"\n"); } if (tasks[colvar::task_extended_lagrangian]) { - if ( !(get_keyval (conf, "extended_x", xr, - colvarvalue (x.type()), colvarparse::parse_silent)) && - !(get_keyval (conf, "extended_v", vr, - colvarvalue (x.type()), colvarparse::parse_silent)) ) { - cvm::log ("Error: restart file does not contain " - "\"extended_x\" or \"extended_v\" for the colvar \""+ - name+"\", but you requested \"extendedLagrangian\".\n"); + if ( !(get_keyval(conf, "extended_x", xr, + colvarvalue(x.type()), colvarparse::parse_silent)) && + !(get_keyval(conf, "extended_v", vr, + colvarvalue(x.type()), colvarparse::parse_silent)) ) { + cvm::log("Error: restart file does not contain " + "\"extended_x\" or \"extended_v\" for the colvar \""+ + name+"\", but you requested \"extendedLagrangian\".\n"); } } if (tasks[task_extended_lagrangian]) { x_reported = xr; } else { x_reported = x; } if (tasks[task_output_velocity]) { - if ( !(get_keyval (conf, "v", v_fdiff, - colvarvalue (x.type()), colvarparse::parse_silent)) ) { - cvm::log ("Error: restart file does not contain " - "the velocity for the colvar \""+ - name+"\", but you requested \"outputVelocity\".\n"); + if ( !(get_keyval(conf, "v", v_fdiff, + colvarvalue(x.type()), colvarparse::parse_silent)) ) { + cvm::log("Error: restart file does not contain " + "the velocity for the colvar \""+ + name+"\", but you requested \"outputVelocity\".\n"); } if (tasks[task_extended_lagrangian]) { v_reported = vr; } else { v_reported = v_fdiff; } } return is; } -std::istream & colvar::read_traj (std::istream &is) +std::istream & colvar::read_traj(std::istream &is) { size_t const start_pos = is.tellg(); if (tasks[task_output_value]) { if (!(is >> x)) { - cvm::log ("Error: in reading the value of colvar \""+ + cvm::log("Error: in reading the value of colvar \""+ this->name+"\" from trajectory.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } if (tasks[task_extended_lagrangian]) { is >> xr; x_reported = xr; } else { x_reported = x; } } if (tasks[task_output_velocity]) { is >> v_fdiff; if (tasks[task_extended_lagrangian]) { is >> vr; v_reported = vr; } else { v_reported = v_fdiff; } } if (tasks[task_output_system_force]) { is >> ft; ft_reported = ft; } if (tasks[task_output_applied_force]) { is >> f; } return is; } // ******************** OUTPUT FUNCTIONS ******************** -std::ostream & colvar::write_restart (std::ostream &os) { +std::ostream & colvar::write_restart(std::ostream &os) { os << "colvar {\n" << " name " << name << "\n" << " x " - << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << x << "\n"; if (tasks[task_output_velocity]) { os << " v " - << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << v_reported << "\n"; } if (tasks[task_extended_lagrangian]) { os << " extended_x " - << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << xr << "\n" << " extended_v " - << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << vr << "\n"; } os << "}\n\n"; return os; } -std::ostream & colvar::write_traj_label (std::ostream & os) +std::ostream & colvar::write_traj_label(std::ostream & os) { - size_t const this_cv_width = x.output_width (cvm::cv_width); + size_t const this_cv_width = x.output_width(cvm::cv_width); os << " "; if (tasks[task_output_value]) { os << " " - << cvm::wrap_string (this->name, this_cv_width); + << cvm::wrap_string(this->name, this_cv_width); if (tasks[task_extended_lagrangian]) { // extended DOF os << " r_" - << cvm::wrap_string (this->name, this_cv_width-2); + << cvm::wrap_string(this->name, this_cv_width-2); } } if (tasks[task_output_velocity]) { os << " v_" - << cvm::wrap_string (this->name, this_cv_width-2); + << cvm::wrap_string(this->name, this_cv_width-2); if (tasks[task_extended_lagrangian]) { // extended DOF os << " vr_" - << cvm::wrap_string (this->name, this_cv_width-3); + << cvm::wrap_string(this->name, this_cv_width-3); } } if (tasks[task_output_energy]) { os << " Ep_" - << cvm::wrap_string (this->name, this_cv_width-3) + << cvm::wrap_string(this->name, this_cv_width-3) << " Ek_" - << cvm::wrap_string (this->name, this_cv_width-3); + << cvm::wrap_string(this->name, this_cv_width-3); } if (tasks[task_output_system_force]) { os << " fs_" - << cvm::wrap_string (this->name, this_cv_width-3); + << cvm::wrap_string(this->name, this_cv_width-3); } if (tasks[task_output_applied_force]) { os << " fa_" - << cvm::wrap_string (this->name, this_cv_width-3); + << cvm::wrap_string(this->name, this_cv_width-3); } return os; } -std::ostream & colvar::write_traj (std::ostream &os) +std::ostream & colvar::write_traj(std::ostream &os) { os << " "; if (tasks[task_output_value]) { if (tasks[task_extended_lagrangian]) { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << x; } os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << x_reported; } if (tasks[task_output_velocity]) { if (tasks[task_extended_lagrangian]) { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << v_fdiff; } os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << v_reported; } if (tasks[task_output_energy]) { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << potential_energy << " " << kinetic_energy; } if (tasks[task_output_system_force]) { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << ft_reported; } if (tasks[task_output_applied_force]) { if (tasks[task_extended_lagrangian]) { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << fr; } else { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << f; } } return os; } int colvar::write_output_files() { if (cvm::b_analysis) { if (acf.size()) { - cvm::log ("Writing acf to file \""+acf_outfile+"\".\n"); + cvm::log("Writing acf to file \""+acf_outfile+"\".\n"); - std::ofstream acf_os (acf_outfile.c_str()); + std::ofstream acf_os(acf_outfile.c_str()); if (! acf_os.good()) { cvm::error("Cannot open file \""+acf_outfile+"\".\n", FILE_ERROR); } - write_acf (acf_os); + write_acf(acf_os); acf_os.close(); } if (runave_os.good()) { runave_os.close(); } } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } // ******************** ANALYSIS FUNCTIONS ******************** void colvar::analyse() { if (tasks[task_runave]) { calc_runave(); } if (tasks[task_corrfunc]) { calc_acf(); } } -inline void history_add_value (size_t const &history_length, +inline void history_add_value(size_t const &history_length, std::list &history, colvarvalue const &new_value) { - history.push_front (new_value); + history.push_front(new_value); if (history.size() > history_length) history.pop_back(); } -inline void history_incr (std::list< std::list > &history, +inline void history_incr(std::list< std::list > &history, std::list< std::list >::iterator &history_p) { if ((++history_p) == history.end()) history_p = history.begin(); } int colvar::calc_acf() { // using here an acf_stride-long list of vectors for either - // coordinates (acf_x_history) or velocities (acf_v_history); each vector can + // coordinates(acf_x_history) or velocities (acf_v_history); each vector can // contain up to acf_length values, which are contiguous in memory // representation but separated by acf_stride in the time series; // the pointer to each vector is changed at every step 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) : + cvm::colvar_by_name(acf_colvar_name) : this); - if (cfcv->type() != this->type()) { - cvm::error ("Error: correlation function between \""+cfcv->name+ - "\" and \""+this->name+"\" cannot be calculated, " - "because their value types are different.\n", - INPUT_ERROR); + if (colvarvalue::check_types(cfcv->value(), value())) { + cvm::error("Error: correlation function between \""+cfcv->name+ + "\" and \""+this->name+"\" cannot be calculated, " + "because their value types are different.\n", + INPUT_ERROR); } acf_nframes = 0; - cvm::log ("Colvar \""+this->name+"\": initializing ACF calculation.\n"); + cvm::log("Colvar \""+this->name+"\": initializing ACF calculation.\n"); if (acf.size() < acf_length+1) - acf.resize (acf_length+1, 0.0); + acf.resize(acf_length+1, 0.0); size_t i; switch (acf_type) { case acf_vel: // allocate space for the velocities history for (i = 0; i < acf_stride; i++) { - acf_v_history.push_back (std::list()); + acf_v_history.push_back(std::list()); } acf_v_history_p = acf_v_history.begin(); break; case acf_coor: case acf_p2coor: // allocate space for the coordinates history for (i = 0; i < acf_stride; i++) { - acf_x_history.push_back (std::list()); + acf_x_history.push_back(std::list()); } acf_x_history_p = acf_x_history.begin(); break; default: break; } } else { colvar *cfcv = (acf_colvar_name.size() ? - cvm::colvar_by_name (acf_colvar_name) : + cvm::colvar_by_name(acf_colvar_name) : this); switch (acf_type) { case acf_vel: if (tasks[task_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()); + v_reported = v_fdiff = fdiff_velocity(x_old, cfcv->value()); } - calc_vel_acf ((*acf_v_history_p), cfcv->velocity()); + 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()); + history_add_value(acf_length+acf_offset, *acf_v_history_p, cfcv->velocity()); // if stride is larger than one, cycle among different histories - history_incr (acf_v_history, acf_v_history_p); + 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_incr (acf_x_history, acf_x_history_p); + calc_coor_acf((*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_incr (acf_x_history, acf_x_history_p); + calc_p2coor_acf((*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; default: break; } } if (tasks[task_fdiff_velocity]) { // set it for the next step x_old = x; } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -int colvar::calc_vel_acf (std::list &v_list, +int colvar::calc_vel_acf(std::list &v_list, colvarvalue const &v) { // loop over stored velocities and add to the ACF, but only the // length is sufficient to hold an entire row of ACF values if (v_list.size() >= acf_length+acf_offset) { std::list::iterator vs_i = v_list.begin(); std::vector::iterator acf_i = acf.begin(); for (size_t i = 0; i < acf_offset; i++) ++vs_i; // current vel with itself *(acf_i) += v.norm2(); ++acf_i; // inner products of previous velocities with current (acf_i and // vs_i are updated) - colvarvalue::inner_opt (v, vs_i, v_list.end(), acf_i); + colvarvalue::inner_opt(v, vs_i, v_list.end(), acf_i); acf_nframes++; } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -void colvar::calc_coor_acf (std::list &x_list, +void colvar::calc_coor_acf(std::list &x_list, colvarvalue const &x) { // same as above but for coordinates if (x_list.size() >= acf_length+acf_offset) { std::list::iterator xs_i = x_list.begin(); std::vector::iterator acf_i = acf.begin(); for (size_t i = 0; i < acf_offset; i++) ++xs_i; *(acf_i++) += x.norm2(); - colvarvalue::inner_opt (x, xs_i, x_list.end(), acf_i); + colvarvalue::inner_opt(x, xs_i, x_list.end(), acf_i); acf_nframes++; } } -void colvar::calc_p2coor_acf (std::list &x_list, +void colvar::calc_p2coor_acf(std::list &x_list, colvarvalue const &x) { // same as above but with second order Legendre polynomial instead // of just the scalar product if (x_list.size() >= acf_length+acf_offset) { std::list::iterator xs_i = x_list.begin(); std::vector::iterator acf_i = acf.begin(); for (size_t i = 0; i < acf_offset; i++) ++xs_i; // value of P2(0) = 1 *(acf_i++) += 1.0; - colvarvalue::p2leg_opt (x, xs_i, x_list.end(), acf_i); + colvarvalue::p2leg_opt(x, xs_i, x_list.end(), acf_i); acf_nframes++; } } -void colvar::write_acf (std::ostream &os) +void colvar::write_acf(std::ostream &os) { if (!acf_nframes) - cvm::log ("Warning: ACF was not calculated (insufficient frames).\n"); - os.setf (std::ios::scientific, std::ios::floatfield); + cvm::log("Warning: ACF was not calculated (insufficient frames).\n"); + os.setf(std::ios::scientific, std::ios::floatfield); os << "# Autocorrelation function for collective 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"; - cvm::real const acf_norm = acf.front() / cvm::real (acf_nframes); + cvm::real const acf_norm = acf.front() / cvm::real(acf_nframes); std::vector::iterator acf_i; size_t it = acf_offset; for (acf_i = acf.begin(); acf_i != acf.end(); ++acf_i) { - os << std::setw (cvm::it_width) << acf_stride * (it++) << " " - << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) + os << std::setw(cvm::it_width) << acf_stride * (it++) << " " + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << ( acf_normalize ? - (*acf_i)/(acf_norm * cvm::real (acf_nframes)) : - (*acf_i)/(cvm::real (acf_nframes)) ) << "\n"; + (*acf_i)/(acf_norm * cvm::real(acf_nframes)) : + (*acf_i)/(cvm::real(acf_nframes)) ) << "\n"; } } void colvar::calc_runave() { if (x_history.empty()) { - runave.type (x.type()); + runave.type(value().type()); runave.reset(); // first-step operations if (cvm::debug()) - cvm::log ("Colvar \""+this->name+ + cvm::log("Colvar \""+this->name+ "\": initializing running average calculation.\n"); acf_nframes = 0; - x_history.push_back (std::list()); + x_history.push_back(std::list()); x_history_p = x_history.begin(); } else { if ( (cvm::step_relative() % runave_stride) == 0) { if ((*x_history_p).size() >= runave_length-1) { runave = x; std::list::iterator xs_i; for (xs_i = (*x_history_p).begin(); xs_i != (*x_history_p).end(); ++xs_i) { runave += (*xs_i); } - runave *= 1.0 / cvm::real (runave_length); + runave *= 1.0 / cvm::real(runave_length); runave.apply_constraints(); runave_variance = 0.0; - runave_variance += this->dist2 (x, runave); + runave_variance += this->dist2(x, runave); for (xs_i = (*x_history_p).begin(); xs_i != (*x_history_p).end(); ++xs_i) { - runave_variance += this->dist2 (x, (*xs_i)); + runave_variance += this->dist2(x, (*xs_i)); } - runave_variance *= 1.0 / cvm::real (runave_length-1); + runave_variance *= 1.0 / cvm::real(runave_length-1); - runave_os << std::setw (cvm::it_width) << cvm::step_relative() + runave_os << std::setw(cvm::it_width) << cvm::step_relative() << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << runave << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) - << std::sqrt (runave_variance) << "\n"; + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) + << std::sqrt(runave_variance) << "\n"; } - history_add_value (runave_length, *x_history_p, x); + history_add_value(runave_length, *x_history_p, x); } } } diff --git a/lib/colvars/colvar.h b/lib/colvars/colvar.h index 3d06cf8df..bb7d70d09 100644 --- a/lib/colvars/colvar.h +++ b/lib/colvars/colvar.h @@ -1,577 +1,578 @@ /// -*- c++ -*- #ifndef COLVAR_H #define COLVAR_H #include #include #include #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" /// \brief A collective variable (main class); to be defined, it needs /// at least one object of a derived class of colvar::cvc; it /// calculates and returns a \link colvarvalue \endlink object /// /// This class parses the configuration, defines the behaviour and /// stores the value (\link colvar::x \endlink) and all related data /// of a collective variable. How the value is calculated is defined /// in \link colvar::cvc \endlink and its derived classes. The /// \link colvar \endlink object contains pointers to multiple \link /// colvar::cvc \endlink derived objects, which can be combined /// together into one collective variable. This makes possible to /// implement new collective variables at runtime based on the /// existing ones. Currently, this possibility is limited to a /// polynomial, using the coefficients cvc::sup_coeff and the /// exponents cvc::sup_np. In case of non-scalar variables, /// only exponents equal to 1 are accepted. /// /// Please note that most of its members are \link colvarvalue /// \endlink objects, i.e. they can handle different data types -/// together, and must all be set to the same type of colvar::x by -/// using the colvarvalue::type() member function before using them -/// together in assignments or other operations; this is usually done +/// together, and must all be set to the same type of colvar::value() +/// before using them together in assignments or other operations; this is usually done /// automatically in the constructor. If you add a new member of /// \link colvarvalue \endlink type, you should also add its /// initialization line in the \link colvar \endlink constructor. class colvar : public colvarparse { public: /// Name std::string name; - /// Type of value - colvarvalue::Type type() const; - - /// \brief Current value (previously obtained from calc() or read_traj()) + /// \brief Current value (previously set by calc() or by read_traj()) colvarvalue const & value() const; /// \brief Current actual value (not extended DOF) colvarvalue const & actual_value() const; - /// \brief Current velocity (previously obtained from calc() or read_traj()) + /// \brief Current velocity (previously set by calc() or by read_traj()) colvarvalue const & velocity() const; /// \brief Current system force (previously obtained from calc() or /// read_traj()). Note: this is calculated using the atomic forces /// from the last simulation step. /// /// Total atom forces are read from the MD program, the total force /// acting on the collective variable is calculated summing those /// from all colvar components, the bias and walls forces are /// subtracted. colvarvalue const & system_force() const; /// \brief /// \brief Typical fluctuation amplitude for this collective /// variable (e.g. local width of a free energy basin) /// /// In metadynamics calculations, \link colvarbias_meta \endlink, /// this value is used to calculate the width of a gaussian. In ABF /// calculations, \link colvarbias_abf \endlink, it is used to /// calculate the grid spacing in the direction of this collective /// variable. cvm::real width; /// \brief True if this \link colvar \endlink is a linear /// 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 this \link colvar \endlink is a linear + /// combination of cvcs with coefficients 1 or -1 + bool b_homogeneous; /// \brief True if all \link cvc \endlink objects are capable /// of calculating inverse gradients bool b_inverse_gradients; /// \brief True if all \link cvc \endlink objects are capable /// of calculating Jacobian forces bool b_Jacobian_force; /// \brief Options controlling the behaviour of the colvar during /// the simulation, which are set from outside the cvcs enum task { /// \brief Gradients are calculated and temporarily stored, so /// that external forces can be applied task_gradients, /// \brief Collect atomic gradient data from all cvcs into vector /// atomic_gradients task_collect_gradients, /// \brief Calculate the velocity with finite differences task_fdiff_velocity, /// \brief The system force is calculated, projecting the atomic /// forces on the inverse gradients task_system_force, /// \brief The variable has a harmonic restraint around a moving /// center with fictitious mass; bias forces will be applied to /// the center task_extended_lagrangian, /// \brief The extended system coordinate undergoes Langevin /// dynamics task_langevin, /// \brief Output the potential and kinetic energies /// (for extended Lagrangian colvars only) task_output_energy, /// \brief Compute analytically the "force" arising from the /// geometric entropy component (for example, that from the angular /// states orthogonal to a distance vector) task_Jacobian_force, /// \brief Report the Jacobian force as part of the system force /// if disabled, apply a correction internally to cancel it task_report_Jacobian_force, /// \brief Output the value to the trajectory file (on by default) task_output_value, /// \brief Output the velocity to the trajectory file task_output_velocity, /// \brief Output the applied force to the trajectory file task_output_applied_force, /// \brief Output the system force to the trajectory file task_output_system_force, /// \brief A lower boundary is defined task_lower_boundary, /// \brief An upper boundary is defined task_upper_boundary, /// \brief Provide a discretization of the values of the colvar to /// be used by the biases or in analysis (needs lower and upper /// boundary) task_grid, /// \brief Apply a restraining potential (|x-xb|^2) to the colvar /// when it goes below the lower wall task_lower_wall, /// \brief Apply a restraining potential (|x-xb|^2) to the colvar /// when it goes above the upper wall task_upper_wall, /// \brief Compute running average task_runave, /// \brief Compute time correlation function task_corrfunc, /// \brief Value and gradients computed by user script task_scripted, /// \brief Number of possible tasks task_ntot }; /// Tasks performed by this colvar bool tasks[task_ntot]; /// List of biases that depend on this colvar std::vector biases; protected: /* extended: H = H_{0} + \sum_{i} 1/2*\lambda*(S_i(x(t))-s_i(t))^2 \\ + \sum_{i} 1/2*m_i*(ds_i(t)/dt)^2 \\ - + \sum_{t' 0.0) ? (1.0/dt) : 1.0 ) * - 0.5 * dist2_lgrad (xnew, xold) ); + 0.5 * dist2_lgrad(xnew, xold) ); } /// Cached reported velocity colvarvalue v_reported; // Options for task_extended_lagrangian /// Restraint center colvarvalue xr; /// Velocity of the restraint center colvarvalue vr; /// Mass of the restraint center cvm::real ext_mass; /// Restraint force constant cvm::real ext_force_k; /// Friction coefficient for Langevin extended dynamics cvm::real ext_gamma; /// Amplitude of Gaussian white noise for Langevin extended dynamics cvm::real ext_sigma; /// \brief Harmonic restraint force colvarvalue fr; /// \brief Jacobian force, when task_Jacobian_force is enabled colvarvalue fj; /// Cached reported system force colvarvalue ft_reported; public: /// \brief Bias force; reset_bias_force() should be called before /// the biases are updated colvarvalue fb; /// \brief Total \em applied force; fr (if task_extended_lagrangian /// is defined), fb (if biases are applied) and the walls' forces /// (if defined) contribute to it colvarvalue f; /// \brief Total force, as derived from the atomic trajectory; /// should equal the total system force plus \link f \endlink colvarvalue ft; /// Period, if it is a constant cvm::real period; /// \brief Same as above, but also takes into account components /// with a variable period, such as distanceZ bool b_periodic; /// \brief Expand the boundaries of multiples of width, to keep the /// value always within range bool expand_boundaries; /// \brief Location of the lower boundary colvarvalue lower_boundary; /// \brief Location of the lower wall colvarvalue lower_wall; /// \brief Force constant for the lower boundary potential (|x-xb|^2) cvm::real lower_wall_k; /// \brief Whether this colvar has a hard lower boundary bool hard_lower_boundary; /// \brief Location of the upper boundary colvarvalue upper_boundary; /// \brief Location of the upper wall colvarvalue upper_wall; /// \brief Force constant for the upper boundary potential (|x-xb|^2) cvm::real upper_wall_k; /// \brief Whether this colvar has a hard upper boundary bool hard_upper_boundary; /// \brief Is the interval defined by the two boundaries periodic? bool periodic_boundaries() const; /// \brief Is the interval defined by the two boundaries periodic? - bool periodic_boundaries (colvarvalue const &lb, colvarvalue const &ub) const; + bool periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) const; /// Constructor - colvar (std::string const &conf); + colvar(std::string const &conf); /// Enable the specified task - int enable (colvar::task const &t); + int enable(colvar::task const &t); /// Disable the specified task - void disable (colvar::task const &t); + void disable(colvar::task const &t); /// Get ready for a run and possibly re-initialize internal data void setup(); /// Destructor ~colvar(); /// \brief Calculate the colvar value and all the other requested /// quantities void calc(); /// \brief Calculate just the value, and store it in the argument - void calc_value (colvarvalue &xn); + void calc_value(colvarvalue &xn); /// Set the total biasing force to zero void reset_bias_force(); /// Add to the total force from biases - void add_bias_force (colvarvalue const &force); + void add_bias_force(colvarvalue const &force); /// \brief Collect all forces on this colvar, integrate internal /// equations of motion of internal degrees of freedom; see also /// colvar::communicate_forces() /// return colvar energy if extended Lagrandian active cvm::real update(); /// \brief Communicate forces (previously calculated in /// colvar::update()) to the external degrees of freedom void communicate_forces(); /// \brief Use the internal metrics (as from \link cvc /// \endlink objects) to calculate square distances and gradients /// /// Handles correctly symmetries and periodic boundary conditions - cvm::real dist2 (colvarvalue const &x1, + cvm::real dist2(colvarvalue const &x1, colvarvalue const &x2) const; /// \brief Use the internal metrics (as from \link cvc /// \endlink objects) to calculate square distances and gradients /// /// Handles correctly symmetries and periodic boundary conditions - colvarvalue dist2_lgrad (colvarvalue const &x1, + colvarvalue dist2_lgrad(colvarvalue const &x1, colvarvalue const &x2) const; /// \brief Use the internal metrics (as from \link cvc /// \endlink objects) to calculate square distances and gradients /// /// Handles correctly symmetries and periodic boundary conditions - colvarvalue dist2_rgrad (colvarvalue const &x1, + colvarvalue dist2_rgrad(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 /// /// Handles correctly symmetries and periodic boundary conditions - void wrap (colvarvalue &x) const; + void wrap(colvarvalue &x) const; /// Read the analysis tasks - int parse_analysis (std::string const &conf); + int parse_analysis(std::string const &conf); /// Perform analysis tasks void analyse(); /// Read the value from a collective variable trajectory file - std::istream & read_traj (std::istream &is); + std::istream & read_traj(std::istream &is); /// Output formatted values to the trajectory file - std::ostream & write_traj (std::ostream &os); + std::ostream & write_traj(std::ostream &os); /// Write a label to the trajectory file (comment line) - std::ostream & write_traj_label (std::ostream &os); + std::ostream & write_traj_label(std::ostream &os); /// Read the collective variable from a restart file - std::istream & read_restart (std::istream &is); + std::istream & read_restart(std::istream &is); /// Write the collective variable to a restart file - std::ostream & write_restart (std::ostream &os); + std::ostream & write_restart(std::ostream &os); /// Write output files (if defined, e.g. in analysis mode) int write_output_files(); protected: /// Previous value (to calculate velocities during analysis) colvarvalue x_old; /// Time series of values and velocities used in correlation /// functions std::list< std::list > acf_x_history, acf_v_history; /// Time series of values and velocities used in correlation /// functions (pointers)x std::list< std::list >::iterator acf_x_history_p, acf_v_history_p; /// Time series of values and velocities used in running averages std::list< std::list > x_history; /// Time series of values and velocities used in correlation /// functions (pointers)x std::list< std::list >::iterator x_history_p; /// \brief Collective variable with which the correlation is /// calculated (default: itself) std::string acf_colvar_name; /// Length of autocorrelation function (ACF) size_t acf_length; /// After how many steps the ACF starts size_t acf_offset; /// How many timesteps separate two ACF values size_t acf_stride; /// Number of frames for each ACF point size_t acf_nframes; /// Normalize the ACF to a maximum value of 1? bool acf_normalize; /// ACF values std::vector acf; /// Name of the file to write the ACF std::string acf_outfile; /// Type of autocorrelation function (ACF) enum acf_type_e { /// Unset type acf_notset, /// Velocity ACF, scalar product between v(0) and v(t) acf_vel, /// Coordinate ACF, scalar product between x(0) and x(t) acf_coor, /// \brief Coordinate ACF, second order Legendre polynomial /// between x(0) and x(t) (does not work with scalar numbers) acf_p2coor }; /// Type of autocorrelation function (ACF) acf_type_e acf_type; /// \brief Velocity ACF, scalar product between v(0) and v(t) - int calc_vel_acf (std::list &v_history, + int calc_vel_acf(std::list &v_history, colvarvalue const &v); /// \brief Coordinate ACF, scalar product between x(0) and x(t) /// (does not work with scalar numbers) - void calc_coor_acf (std::list &x_history, + void calc_coor_acf(std::list &x_history, colvarvalue const &x); /// \brief Coordinate ACF, second order Legendre polynomial between /// x(0) and x(t) (does not work with scalar numbers) - void calc_p2coor_acf (std::list &x_history, + void calc_p2coor_acf(std::list &x_history, colvarvalue const &x); /// Calculate the auto-correlation function (ACF) int calc_acf(); /// Save the ACF to a file - void write_acf (std::ostream &os); + void write_acf(std::ostream &os); /// Length of running average series size_t runave_length; /// Timesteps to skip between two values in the running average series size_t runave_stride; /// Name of the file to write the running average std::ofstream runave_os; /// Current value of the running average colvarvalue runave; /// Current value of the square deviation from the running average cvm::real runave_variance; /// Calculate the running average and its standard deviation void calc_runave(); /// If extended Lagrangian active: colvar energies (kinetic and harmonic potential) cvm::real kinetic_energy; cvm::real potential_energy; public: // collective variable component base class class cvc; // currently available collective variable components // scalar colvar components class distance; class distance_z; class distance_xy; class distance_inv; + class distance_pairs; class angle; class dihedral; class coordnum; class selfcoordnum; class h_bond; class rmsd; class orientation_angle; class orientation_proj; class tilt; class spin_angle; class gyration; class inertia; class inertia_z; class eigenvector; class alpha_dihedrals; class alpha_angles; class dihedPC; // non-scalar components class distance_vec; class distance_dir; + class cartesian; class orientation; protected: /// \brief Array of \link cvc \endlink objects std::vector cvcs; /// \brief Initialize the sorted list of atom IDs for atoms involved /// in all cvcs (called when enabling task_collect_gradients) - void build_atom_list (void); + void build_atom_list(void); private: /// Name of scripted function to be used std::string scripted_function; /// Current cvc values in the order requested by script /// when using scriptedFunction std::vector sorted_cvc_values; public: /// \brief Sorted array of (zero-based) IDs for all atoms involved std::vector atom_ids; /// \brief Array of atomic gradients collected from all cvcs /// with appropriate components, rotations etc. /// For scalar variables only! std::vector atomic_gradients; - inline size_t n_components () const { + inline size_t n_components() const { return cvcs.size(); } }; -inline colvarvalue::Type colvar::type() const -{ - return x.type(); -} - inline colvarvalue const & colvar::value() const { return x_reported; } inline colvarvalue const & colvar::actual_value() const { return x; } inline colvarvalue const & colvar::velocity() const { return v_reported; } inline colvarvalue const & colvar::system_force() const { return ft_reported; } -inline void colvar::add_bias_force (colvarvalue const &force) +inline void colvar::add_bias_force(colvarvalue const &force) { fb += force; } inline void colvar::reset_bias_force() { + fb.type(value()); fb.reset(); } #endif diff --git a/lib/colvars/colvaratoms.cpp b/lib/colvars/colvaratoms.cpp index 250d23acf..bd8c50ee3 100644 --- a/lib/colvars/colvaratoms.cpp +++ b/lib/colvars/colvaratoms.cpp @@ -1,897 +1,897 @@ /// -*- c++ -*- #include "colvarmodule.h" #include "colvarparse.h" #include "colvaratoms.h" // member functions of the "atom" class depend tightly on the MD interface, and are // thus defined in colvarproxy_xxx.cpp // in this file only atom_group functions are defined // Note: "conf" is the configuration of the cvc who is using this atom group; // "key" is the name of the atom group (e.g. "atoms", "group1", "group2", ...) -cvm::atom_group::atom_group (std::string const &conf, +cvm::atom_group::atom_group(std::string const &conf, char const *key) - : b_center (false), b_rotate (false), b_user_defined_fit (false), - b_fit_gradients (false), - ref_pos_group (NULL), - noforce (false) + : b_center(false), b_rotate(false), b_user_defined_fit(false), + b_fit_gradients(false), + ref_pos_group(NULL), + noforce(false) { - cvm::log ("Defining atom group \""+ - std::string (key)+"\".\n"); + cvm::log("Defining atom group \""+ + std::string(key)+"\".\n"); // real work is done by parse - parse (conf, key); + parse(conf, key); } -cvm::atom_group::atom_group (std::vector const &atoms) - : b_dummy (false), b_center (false), b_rotate (false), - b_fit_gradients (false), ref_pos_group (NULL), - noforce (false) +cvm::atom_group::atom_group(std::vector const &atoms) + : b_dummy(false), b_center(false), b_rotate(false), + b_fit_gradients(false), ref_pos_group(NULL), + noforce(false) { - this->reserve (atoms.size()); + this->reserve(atoms.size()); for (size_t i = 0; i < atoms.size(); i++) { - this->push_back (atoms[i]); + this->push_back(atoms[i]); } total_mass = 0.0; for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { total_mass += ai->mass; } } cvm::atom_group::atom_group() - : b_dummy (false), b_center (false), b_rotate (false), - b_user_defined_fit (false), b_fit_gradients (false), - ref_pos_group (NULL), noforce (false) + : b_dummy(false), b_center(false), b_rotate(false), + b_user_defined_fit(false), b_fit_gradients(false), + ref_pos_group(NULL), noforce(false) { total_mass = 0.0; } cvm::atom_group::~atom_group() { if (ref_pos_group) { delete ref_pos_group; ref_pos_group = NULL; } } -void cvm::atom_group::add_atom (cvm::atom const &a) +void cvm::atom_group::add_atom(cvm::atom const &a) { if (b_dummy) { - cvm::error ("Error: cannot add atoms to a dummy group.\n", INPUT_ERROR); + cvm::error("Error: cannot add atoms to a dummy group.\n", INPUT_ERROR); } else { - this->push_back (a); + this->push_back(a); total_mass += a.mass; } } void cvm::atom_group::reset_mass(std::string &name, int i, int j) { total_mass = 0.0; for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { total_mass += ai->mass; } - cvm::log ("Re-initialized atom group "+name+":"+cvm::to_str (i)+"/"+ - cvm::to_str (j)+". "+ cvm::to_str (this->size())+ - " atoms: total mass = "+cvm::to_str (this->total_mass)+".\n"); + cvm::log("Re-initialized atom group "+name+":"+cvm::to_str(i)+"/"+ + cvm::to_str(j)+". "+ cvm::to_str(this->size())+ + " atoms: total mass = "+cvm::to_str(this->total_mass)+".\n"); } -int cvm::atom_group::parse (std::string const &conf, +int cvm::atom_group::parse(std::string const &conf, char const *key) { std::string group_conf; // save_delimiters is set to false for this call, because "conf" is // not the config string of this group, but of its parent object // (which has already taken care of the delimiters) save_delimiters = false; - key_lookup (conf, key, group_conf, dummy_pos); + key_lookup(conf, key, group_conf, dummy_pos); // restoring the normal value, because we do want keywords checked // inside "group_conf" save_delimiters = true; if (group_conf.size() == 0) { - cvm::error ("Error: atom group \""+std::string (key)+ + cvm::error("Error: atom group \""+std::string(key)+ "\" is set, but has no definition.\n", INPUT_ERROR); return COLVARS_ERROR; } cvm::increase_depth(); - cvm::log ("Initializing atom group \""+std::string (key)+"\".\n"); + cvm::log("Initializing atom group \""+std::string(key)+"\".\n"); // whether or not to include messages in the log // colvarparse::Parse_Mode mode = parse_silent; // { // bool b_verbose; // get_keyval (group_conf, "verboseOutput", b_verbose, false, parse_silent); // if (b_verbose) mode = parse_normal; // } colvarparse::Parse_Mode mode = parse_normal; { // std::vector atom_indexes; std::string numbers_conf = ""; size_t pos = 0; std::vector atom_indexes; - while (key_lookup (group_conf, "atomNumbers", numbers_conf, pos)) { + while (key_lookup(group_conf, "atomNumbers", numbers_conf, pos)) { if (numbers_conf.size()) { - std::istringstream is (numbers_conf); + std::istringstream is(numbers_conf); int ia; while (is >> ia) { - atom_indexes.push_back (ia); + atom_indexes.push_back(ia); } } if (atom_indexes.size()) { - this->reserve (this->size()+atom_indexes.size()); + this->reserve(this->size()+atom_indexes.size()); for (size_t i = 0; i < atom_indexes.size(); i++) { - this->push_back (cvm::atom (atom_indexes[i])); + this->push_back(cvm::atom(atom_indexes[i])); } if (cvm::get_error()) return COLVARS_ERROR; } else { - cvm::error ("Error: no numbers provided for \"" + cvm::error("Error: no numbers provided for \"" "atomNumbers\".\n", INPUT_ERROR); return COLVARS_ERROR; } atom_indexes.clear(); } std::string index_group_name; - if (get_keyval (group_conf, "indexGroup", index_group_name)) { + if (get_keyval(group_conf, "indexGroup", index_group_name)) { // use an index group from the index file read globally std::list::iterator names_i = cvm::index_group_names.begin(); std::list >::iterator index_groups_i = cvm::index_groups.begin(); for ( ; names_i != cvm::index_group_names.end() ; ++names_i, ++index_groups_i) { if (*names_i == index_group_name) break; } if (names_i == cvm::index_group_names.end()) { - cvm::error ("Error: could not find index group "+ + cvm::error("Error: could not find index group "+ index_group_name+" among those provided by the index file.\n", INPUT_ERROR); return COLVARS_ERROR; } - this->reserve (index_groups_i->size()); + this->reserve(index_groups_i->size()); for (size_t i = 0; i < index_groups_i->size(); i++) { - this->push_back (cvm::atom ((*index_groups_i)[i])); + this->push_back(cvm::atom((*index_groups_i)[i])); } if (cvm::get_error()) return COLVARS_ERROR; } } { std::string range_conf = ""; size_t pos = 0; - while (key_lookup (group_conf, "atomNumbersRange", + while (key_lookup(group_conf, "atomNumbersRange", range_conf, pos)) { if (range_conf.size()) { - std::istringstream is (range_conf); + std::istringstream is(range_conf); int initial, final; char dash; if ( (is >> initial) && (initial > 0) && (is >> dash) && (dash == '-') && (is >> final) && (final > 0) ) { for (int anum = initial; anum <= final; anum++) { - this->push_back (cvm::atom (anum)); + this->push_back(cvm::atom(anum)); } if (cvm::get_error()) return COLVARS_ERROR; range_conf = ""; continue; } } - cvm::error ("Error: no valid definition for \"atomNumbersRange\", \""+ + cvm::error("Error: no valid definition for \"atomNumbersRange\", \""+ range_conf+"\".\n", INPUT_ERROR); } } std::vector psf_segids; - get_keyval (group_conf, "psfSegID", psf_segids, std::vector (), mode); + get_keyval(group_conf, "psfSegID", psf_segids, std::vector (), mode); for (std::vector::iterator psii = psf_segids.begin(); psii < psf_segids.end(); ++psii) { if ( (psii->size() == 0) || (psii->size() > 4) ) { - cvm::error ("Error: invalid segmend identifier provided, \""+ + cvm::error("Error: invalid segmend identifier provided, \""+ (*psii)+"\".\n", INPUT_ERROR); } } { std::string range_conf = ""; size_t pos = 0; size_t range_count = 0; std::vector::iterator psii = psf_segids.begin(); - while (key_lookup (group_conf, "atomNameResidueRange", + while (key_lookup(group_conf, "atomNameResidueRange", range_conf, pos)) { range_count++; if (range_count > psf_segids.size()) { - cvm::error ("Error: more instances of \"atomNameResidueRange\" than " + cvm::error("Error: more instances of \"atomNameResidueRange\" than " "values of \"psfSegID\".\n", INPUT_ERROR); } - std::string const &psf_segid = psf_segids.size() ? *psii : std::string (""); + std::string const &psf_segid = psf_segids.size() ? *psii : std::string(""); if (range_conf.size()) { - std::istringstream is (range_conf); + std::istringstream is(range_conf); std::string atom_name; int initial, final; char dash; if ( (is >> atom_name) && (atom_name.size()) && (is >> initial) && (initial > 0) && (is >> dash) && (dash == '-') && (is >> final) && (final > 0) ) { for (int resid = initial; resid <= final; resid++) { - this->push_back (cvm::atom (resid, atom_name, psf_segid)); + 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 \"" + cvm::error("Error: cannot parse definition for \"" "atomNameResidueRange\", \""+ range_conf+"\".\n"); } } else { - cvm::error ("Error: atomNameResidueRange with empty definition.\n"); + cvm::error("Error: atomNameResidueRange with empty definition.\n"); } if (psf_segid.size()) ++psii; } } { // read the atoms from a file std::string atoms_file_name; - if (get_keyval (group_conf, "atomsFile", atoms_file_name, std::string (""), mode)) { + if (get_keyval(group_conf, "atomsFile", atoms_file_name, std::string(""), mode)) { std::string atoms_col; - if (!get_keyval (group_conf, "atomsCol", atoms_col, std::string (""), mode)) { - cvm::error ("Error: parameter atomsCol is required if atomsFile is set.\n", + if (!get_keyval(group_conf, "atomsCol", atoms_col, std::string(""), mode)) { + cvm::error("Error: parameter atomsCol is required if atomsFile is set.\n", INPUT_ERROR); } double atoms_col_value; - bool const atoms_col_value_defined = get_keyval (group_conf, "atomsColValue", atoms_col_value, 0.0, mode); + bool const atoms_col_value_defined = get_keyval(group_conf, "atomsColValue", atoms_col_value, 0.0, mode); if (atoms_col_value_defined && (!atoms_col_value)) { - cvm::error ("Error: atomsColValue, if provided, must be non-zero.\n", INPUT_ERROR); + cvm::error("Error: atomsColValue, if provided, must be non-zero.\n", INPUT_ERROR); } - cvm::load_atoms (atoms_file_name.c_str(), *this, atoms_col, atoms_col_value); + cvm::load_atoms(atoms_file_name.c_str(), *this, atoms_col, atoms_col_value); } } // Catch any errors from all the initialization steps above if (cvm::get_error()) return COLVARS_ERROR; for (std::vector::iterator a1 = this->begin(); a1 != this->end(); ++a1) { std::vector::iterator a2 = a1; ++a2; for ( ; a2 != this->end(); ++a2) { if (a1->id == a2->id) { if (cvm::debug()) - cvm::log ("Discarding doubly counted atom with number "+ - cvm::to_str (a1->id+1)+".\n"); - a2 = this->erase (a2); + cvm::log("Discarding doubly counted atom with number "+ + cvm::to_str(a1->id+1)+".\n"); + a2 = this->erase(a2); if (a2 == this->end()) break; } } } - if (get_keyval (group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos(), mode)) { + if (get_keyval(group_conf, "dummyAtom", dummy_atom_pos, cvm::atom_pos(), mode)) { b_dummy = true; this->total_mass = 1.0; } else b_dummy = false; if (b_dummy && (this->size())) { - cvm::error ("Error: cannot set up group \""+ - std::string (key)+"\" as a dummy atom " + cvm::error("Error: cannot set up group \""+ + std::string(key)+"\" as a dummy atom " "and provide it with atom definitions.\n", INPUT_ERROR); } -#if (! defined (COLVARS_STANDALONE)) +#if(! defined(COLVARS_STANDALONE)) if ( (!b_dummy) && (!cvm::b_analysis) && (!(this->size())) ) { - cvm::error ("Error: no atoms defined for atom group \""+ - std::string (key)+"\".\n"); + cvm::error("Error: no atoms defined for atom group \""+ + std::string(key)+"\".\n"); } #endif if (!b_dummy) { this->total_mass = 0.0; for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { this->total_mass += ai->mass; } } if (!b_dummy) { bool enable_forces = true; // disableForces is deprecated - if (get_keyval (group_conf, "enableForces", enable_forces, true, mode)) { + if (get_keyval(group_conf, "enableForces", enable_forces, true, mode)) { noforce = !enable_forces; } else { - get_keyval (group_conf, "disableForces", noforce, false, mode); + get_keyval(group_conf, "disableForces", noforce, false, mode); } } // FITTING OPTIONS - bool b_defined_center = get_keyval (group_conf, "centerReference", b_center, false, mode); - bool b_defined_rotate = get_keyval (group_conf, "rotateReference", b_rotate, false, mode); + bool b_defined_center = get_keyval(group_conf, "centerReference", b_center, false, mode); + bool b_defined_rotate = get_keyval(group_conf, "rotateReference", b_rotate, false, mode); // is the user setting explicit options? b_user_defined_fit = b_defined_center || b_defined_rotate; - get_keyval (group_conf, "enableFitGradients", b_fit_gradients, true, mode); + get_keyval(group_conf, "enableFitGradients", b_fit_gradients, true, mode); if (b_center || b_rotate) { if (b_dummy) - cvm::error ("Error: centerReference or rotateReference " + cvm::error("Error: centerReference or rotateReference " "cannot be defined for a dummy atom.\n"); - if (key_lookup (group_conf, "refPositionsGroup")) { + if (key_lookup(group_conf, "refPositionsGroup")) { // instead of this group, define another group to compute the fit if (ref_pos_group) { - cvm::error ("Error: the atom group \""+ - std::string (key)+"\" has already a reference group " + cvm::error("Error: the atom group \""+ + std::string(key)+"\" has already a reference group " "for the rototranslational fit, which was communicated by the " "colvar component. You should not use refPositionsGroup " "in this case.\n"); } - cvm::log ("Within atom group \""+std::string (key)+"\":\n"); - ref_pos_group = new atom_group (group_conf, "refPositionsGroup"); + cvm::log("Within atom group \""+std::string(key)+"\":\n"); + ref_pos_group = new atom_group(group_conf, "refPositionsGroup"); // regardless of the configuration, fit gradients must be calculated by refPositionsGroup ref_pos_group->b_fit_gradients = this->b_fit_gradients; this->b_fit_gradients = false; } atom_group *group_for_fit = ref_pos_group ? ref_pos_group : this; - get_keyval (group_conf, "refPositions", ref_pos, ref_pos, mode); + get_keyval(group_conf, "refPositions", ref_pos, ref_pos, mode); std::string ref_pos_file; - if (get_keyval (group_conf, "refPositionsFile", ref_pos_file, std::string (""), mode)) { + if (get_keyval(group_conf, "refPositionsFile", ref_pos_file, std::string(""), mode)) { if (ref_pos.size()) { - cvm::error ("Error: cannot specify \"refPositionsFile\" and " + cvm::error("Error: cannot specify \"refPositionsFile\" and " "\"refPositions\" at the same time.\n"); } std::string ref_pos_col; double ref_pos_col_value; - if (get_keyval (group_conf, "refPositionsCol", ref_pos_col, std::string (""), mode)) { + if (get_keyval(group_conf, "refPositionsCol", ref_pos_col, std::string(""), mode)) { // if provided, use PDB column to select coordinates - bool found = get_keyval (group_conf, "refPositionsColValue", ref_pos_col_value, 0.0, mode); + bool found = get_keyval(group_conf, "refPositionsColValue", ref_pos_col_value, 0.0, mode); if (found && !ref_pos_col_value) - cvm::error ("Error: refPositionsColValue, " + cvm::error("Error: refPositionsColValue, " "if provided, must be non-zero.\n"); } else { // if not, rely on existing atom indices for the group group_for_fit->create_sorted_ids(); - ref_pos.resize (group_for_fit->size()); + ref_pos.resize(group_for_fit->size()); } - cvm::load_coords (ref_pos_file.c_str(), ref_pos, group_for_fit->sorted_ids, + cvm::load_coords(ref_pos_file.c_str(), ref_pos, group_for_fit->sorted_ids, ref_pos_col, ref_pos_col_value); } if (ref_pos.size()) { if (b_rotate) { if (ref_pos.size() != group_for_fit->size()) - cvm::error ("Error: the number of reference positions provided ("+ - cvm::to_str (ref_pos.size())+ + cvm::error("Error: the number of reference positions provided("+ + cvm::to_str(ref_pos.size())+ ") does not match the number of atoms within \""+ - std::string (key)+ - "\" ("+cvm::to_str (group_for_fit->size())+ + std::string(key)+ + "\" ("+cvm::to_str(group_for_fit->size())+ "): to perform a rotational fit, "+ "these numbers should be equal.\n", INPUT_ERROR); } // save the center of geometry of ref_pos and subtract it center_ref_pos(); } else { -#if (! defined (COLVARS_STANDALONE)) - cvm::error ("Error: no reference positions provided.\n"); +#if(! defined(COLVARS_STANDALONE)) + cvm::error("Error: no reference positions provided.\n"); #endif } if (b_fit_gradients) { - group_for_fit->fit_gradients.assign (group_for_fit->size(), cvm::atom_pos (0.0, 0.0, 0.0)); - rot.request_group1_gradients (group_for_fit->size()); + group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0)); + rot.request_group1_gradients(group_for_fit->size()); } if (b_rotate && !noforce) { - cvm::log ("Warning: atom group \""+std::string (key)+ + cvm::log("Warning: atom group \""+std::string(key)+ "\" will be aligned to a fixed orientation given by the reference positions provided. " "If the internal structure of the group changes too much (i.e. its RMSD is comparable " "to its radius of gyration), the optimal rotation and its gradients may become discontinuous. " "If that happens, use refPositionsGroup (or a different definition for it if already defined) " "to align the coordinates.\n"); // initialize rot member data - rot.request_group1_gradients (this->size()); + rot.request_group1_gradients(this->size()); } } if (cvm::debug()) - cvm::log ("Done initializing atom group with name \""+ - std::string (key)+"\".\n"); + cvm::log("Done initializing atom group with name \""+ + std::string(key)+"\".\n"); - this->check_keywords (group_conf, key); + this->check_keywords(group_conf, key); if (cvm::get_error()) { - cvm::error("Error setting up atom group \""+std::string (key)+"\"."); + 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 = "+ - cvm::to_str (this->total_mass)+".\n"); + cvm::log("Atom group \""+std::string(key)+"\" defined, "+ + cvm::to_str(this->size())+" atoms initialized: total mass = "+ + cvm::to_str(this->total_mass)+".\n"); cvm::decrease_depth(); return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -int cvm::atom_group::create_sorted_ids (void) +int cvm::atom_group::create_sorted_ids(void) { // Only do the work if the vector is not yet populated if (sorted_ids.size()) return COLVARS_OK; std::list temp_id_list; cvm::atom_iter ai; for (ai = this->begin(); ai != this->end(); ai++) { - temp_id_list.push_back (ai->id); + temp_id_list.push_back(ai->id); } temp_id_list.sort(); temp_id_list.unique(); if (temp_id_list.size() != this->size()) { - cvm::error ("Error: duplicate atom IDs in atom group? (found " + + cvm::error("Error: duplicate atom IDs in atom group? (found " + cvm::to_str(temp_id_list.size()) + " unique atom IDs instead of" + cvm::to_str(this->size()) + ").\n"); return COLVARS_ERROR; } sorted_ids = std::vector (temp_id_list.size()); unsigned int id_i = 0; std::list::iterator li; for (li = temp_id_list.begin(); li != temp_id_list.end(); ++li) { sorted_ids[id_i] = *li; id_i++; } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } void cvm::atom_group::center_ref_pos() { // save the center of geometry of ref_pos and then subtract it from // them; in this way it will be possible to use ref_pos also for // the rotational fit // This is called either by atom_group::parse or by CVCs that set // reference positions (eg. RMSD, eigenvector) - ref_pos_cog = cvm::atom_pos (0.0, 0.0, 0.0); + ref_pos_cog = cvm::atom_pos(0.0, 0.0, 0.0); std::vector::iterator pi; for (pi = ref_pos.begin(); pi != ref_pos.end(); ++pi) { ref_pos_cog += *pi; } ref_pos_cog /= (cvm::real) ref_pos.size(); for (pi = ref_pos.begin(); pi != ref_pos.end(); ++pi) { (*pi) -= ref_pos_cog; } } void cvm::atom_group::read_positions() { if (b_dummy) return; for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->read_position(); } if (ref_pos_group) ref_pos_group->read_positions(); } void cvm::atom_group::calc_apply_roto_translation() { atom_group *fit_group = ref_pos_group ? ref_pos_group : this; if (b_center) { // center on the origin first cvm::atom_pos const cog = fit_group->center_of_geometry(); for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->pos -= cog; } } if (b_rotate) { // rotate the group (around the center of geometry if b_center is // true, around the origin otherwise) - rot.calc_optimal_rotation (fit_group->positions(), ref_pos); + rot.calc_optimal_rotation(fit_group->positions(), ref_pos); for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { - ai->pos = rot.rotate (ai->pos); + ai->pos = rot.rotate(ai->pos); } } if (b_center) { // align with the center of geometry of ref_pos for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->pos += ref_pos_cog; } } } -void cvm::atom_group::apply_translation (cvm::rvector const &t) +void cvm::atom_group::apply_translation(cvm::rvector const &t) { if (b_dummy) return; for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->pos += t; } } -void cvm::atom_group::apply_rotation (cvm::rotation const &rot) +void cvm::atom_group::apply_rotation(cvm::rotation const &rot) { if (b_dummy) return; for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { - ai->pos = rot.rotate (ai->pos); + ai->pos = rot.rotate(ai->pos); } } void cvm::atom_group::read_velocities() { if (b_dummy) return; if (b_rotate) { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->read_velocity(); - ai->vel = rot.rotate (ai->vel); + ai->vel = rot.rotate(ai->vel); } } else { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->read_velocity(); } } } void cvm::atom_group::read_system_forces() { if (b_dummy) return; if (b_rotate) { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->read_system_force(); - ai->system_force = rot.rotate (ai->system_force); + ai->system_force = rot.rotate(ai->system_force); } } else { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->read_system_force(); } } } cvm::atom_pos cvm::atom_group::center_of_geometry() const { if (b_dummy) return dummy_atom_pos; - cvm::atom_pos cog (0.0, 0.0, 0.0); + cvm::atom_pos cog(0.0, 0.0, 0.0); for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) { cog += ai->pos; } cog /= this->size(); return cog; } cvm::atom_pos cvm::atom_group::center_of_mass() const { if (b_dummy) return dummy_atom_pos; - cvm::atom_pos com (0.0, 0.0, 0.0); + cvm::atom_pos com(0.0, 0.0, 0.0); for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) { com += ai->mass * ai->pos; } com /= this->total_mass; return com; } -void cvm::atom_group::set_weighted_gradient (cvm::rvector const &grad) +void cvm::atom_group::set_weighted_gradient(cvm::rvector const &grad) { if (b_dummy) return; for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { ai->grad = (ai->mass/this->total_mass) * grad; } } void cvm::atom_group::calc_fit_gradients() { if (b_dummy) return; if ((!b_center) && (!b_rotate)) return; // no fit if (cvm::debug()) - cvm::log ("Calculating fit gradients.\n"); + cvm::log("Calculating fit gradients.\n"); atom_group *group_for_fit = ref_pos_group ? ref_pos_group : this; - group_for_fit->fit_gradients.assign (group_for_fit->size(), cvm::rvector (0.0, 0.0, 0.0)); + group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::rvector(0.0, 0.0, 0.0)); if (b_center) { // add the center of geometry contribution to the gradients for (size_t i = 0; i < this->size(); i++) { // need to bring the gradients in original frame first cvm::rvector const atom_grad = b_rotate ? - (rot.inverse()).rotate ((*this)[i].grad) : + (rot.inverse()).rotate((*this)[i].grad) : (*this)[i].grad; for (size_t j = 0; j < group_for_fit->size(); j++) { group_for_fit->fit_gradients[j] += - (-1.0)/(cvm::real (group_for_fit->size())) * + (-1.0)/(cvm::real(group_for_fit->size())) * atom_grad; } } } if (b_rotate) { // add the rotation matrix contribution to the gradients cvm::rotation const rot_inv = rot.inverse(); cvm::atom_pos const cog = this->center_of_geometry(); for (size_t i = 0; i < this->size(); i++) { - cvm::atom_pos const pos_orig = rot_inv.rotate ((b_center ? ((*this)[i].pos - cog) : ((*this)[i].pos))); + cvm::atom_pos const pos_orig = rot_inv.rotate((b_center ? ((*this)[i].pos - cog) : ((*this)[i].pos))); for (size_t j = 0; j < group_for_fit->size(); j++) { // calculate \partial(R(q) \vec{x}_i)/\partial q) \cdot \partial\xi/\partial\vec{x}_i cvm::quaternion const dxdq = - rot.q.position_derivative_inner (pos_orig, (*this)[i].grad); + rot.q.position_derivative_inner(pos_orig, (*this)[i].grad); // multiply by \cdot {\partial q}/\partial\vec{x}_j and add it to the fit gradients for (size_t iq = 0; iq < 4; iq++) { group_for_fit->fit_gradients[j] += dxdq[iq] * rot.dQ0_1[j][iq]; } } } } if (cvm::debug()) - cvm::log ("Done calculating fit gradients.\n"); + cvm::log("Done calculating fit gradients.\n"); } std::vector cvm::atom_group::positions() const { if (b_dummy) { - cvm::error ("Error: positions are not available " + cvm::error("Error: positions are not available " "from a dummy atom group.\n"); } - std::vector x (this->size(), 0.0); + std::vector x(this->size(), 0.0); cvm::atom_const_iter ai = this->begin(); std::vector::iterator xi = x.begin(); for ( ; ai != this->end(); ++xi, ++ai) { *xi = ai->pos; } return x; } -std::vector cvm::atom_group::positions_shifted (cvm::rvector const &shift) const +std::vector cvm::atom_group::positions_shifted(cvm::rvector const &shift) const { if (b_dummy) { - cvm::error ("Error: positions are not available " + cvm::error("Error: positions are not available " "from a dummy atom group.\n"); } - std::vector x (this->size(), 0.0); + std::vector x(this->size(), 0.0); cvm::atom_const_iter ai = this->begin(); std::vector::iterator xi = x.begin(); for ( ; ai != this->end(); ++xi, ++ai) { *xi = (ai->pos + shift); } return x; } std::vector cvm::atom_group::velocities() const { if (b_dummy) { - cvm::error ("Error: velocities are not available " + cvm::error("Error: velocities are not available " "from a dummy atom group.\n"); } - std::vector v (this->size(), 0.0); + std::vector v(this->size(), 0.0); cvm::atom_const_iter ai = this->begin(); std::vector::iterator vi = v.begin(); for ( ; ai != this->end(); vi++, ai++) { *vi = ai->vel; } return v; } std::vector cvm::atom_group::system_forces() const { if (b_dummy) { - cvm::error ("Error: system forces are not available " + cvm::error("Error: system forces are not available " "from a dummy atom group.\n"); } - std::vector f (this->size(), 0.0); + std::vector f(this->size(), 0.0); cvm::atom_const_iter ai = this->begin(); std::vector::iterator fi = f.begin(); for ( ; ai != this->end(); ++fi, ++ai) { *fi = ai->system_force; } return f; } cvm::rvector cvm::atom_group::system_force() const { if (b_dummy) { - cvm::error ("Error: system forces are not available " + cvm::error("Error: system forces are not available " "from a dummy atom group.\n"); } - cvm::rvector f (0.0); + cvm::rvector f(0.0); for (cvm::atom_const_iter ai = this->begin(); ai != this->end(); ai++) { f += ai->system_force; } return f; } -void cvm::atom_group::apply_colvar_force (cvm::real const &force) +void cvm::atom_group::apply_colvar_force(cvm::real const &force) { if (b_dummy) return; if (noforce) { - cvm::error ("Error: sending a force to a group that has " + cvm::error("Error: sending a force to a group that has " "\"enableForces\" set to off.\n"); return; } if (b_rotate) { // rotate forces back to the original frame cvm::rotation const rot_inv = rot.inverse(); for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { - ai->apply_force (rot_inv.rotate (force * ai->grad)); + ai->apply_force(rot_inv.rotate(force * ai->grad)); } } else { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { - ai->apply_force (force * ai->grad); + ai->apply_force(force * ai->grad); } } if ((b_center || b_rotate) && b_fit_gradients) { atom_group *group_for_fit = ref_pos_group ? ref_pos_group : this; // add the contribution from the roto-translational fit to the gradients if (b_rotate) { // rotate forces back to the original frame cvm::rotation const rot_inv = rot.inverse(); for (size_t j = 0; j < group_for_fit->size(); j++) { - (*group_for_fit)[j].apply_force (rot_inv.rotate (force * group_for_fit->fit_gradients[j])); + (*group_for_fit)[j].apply_force(rot_inv.rotate(force * group_for_fit->fit_gradients[j])); } } else { for (size_t j = 0; j < group_for_fit->size(); j++) { - (*group_for_fit)[j].apply_force (force * group_for_fit->fit_gradients[j]); + (*group_for_fit)[j].apply_force(force * group_for_fit->fit_gradients[j]); } } } } -void cvm::atom_group::apply_force (cvm::rvector const &force) +void cvm::atom_group::apply_force(cvm::rvector const &force) { if (b_dummy) return; if (noforce) { - cvm::error ("Error: sending a force to a group that has " + cvm::error("Error: sending a force to a group that has " "\"disableForces\" defined.\n"); return; } if (b_rotate) { cvm::rotation const rot_inv = rot.inverse(); for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { - ai->apply_force (rot_inv.rotate ((ai->mass/this->total_mass) * force)); + ai->apply_force(rot_inv.rotate((ai->mass/this->total_mass) * force)); } } else { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) { - ai->apply_force ((ai->mass/this->total_mass) * force); + ai->apply_force((ai->mass/this->total_mass) * force); } } } -void cvm::atom_group::apply_forces (std::vector const &forces) +void cvm::atom_group::apply_forces(std::vector const &forces) { if (b_dummy) return; if (noforce) - cvm::error ("Error: sending a force to a group that has " + cvm::error("Error: sending a force to a group that has " "\"disableForces\" defined.\n"); if (forces.size() != this->size()) { - cvm::error ("Error: trying to apply an array of forces to an atom " + cvm::error("Error: trying to apply an array of forces to an atom " "group which does not have the same length.\n"); } if (b_rotate) { cvm::rotation const rot_inv = rot.inverse(); cvm::atom_iter ai = this->begin(); std::vector::const_iterator fi = forces.begin(); for ( ; ai != this->end(); ++fi, ++ai) { - ai->apply_force (rot_inv.rotate (*fi)); + ai->apply_force(rot_inv.rotate(*fi)); } } else { cvm::atom_iter ai = this->begin(); std::vector::const_iterator fi = forces.begin(); for ( ; ai != this->end(); ++fi, ++ai) { - ai->apply_force (*fi); + ai->apply_force(*fi); } } } diff --git a/lib/colvars/colvaratoms.h b/lib/colvars/colvaratoms.h index 663871ffa..5a44d106c 100644 --- a/lib/colvars/colvaratoms.h +++ b/lib/colvars/colvaratoms.h @@ -1,332 +1,332 @@ /// -*- c++ -*- #ifndef COLVARATOMS_H #define COLVARATOMS_H #include "colvarmodule.h" #include "colvarparse.h" /// \brief Stores numeric id, mass and all mutable data for an atom, /// mostly used by a \link cvc \endlink /// /// This class may be used (although not necessarily) to keep atomic /// data (id, mass, position and collective variable derivatives) /// altogether. There may be multiple instances with identical /// numeric id, all acting independently: forces communicated through /// these instances will be summed together. /// /// Read/write operations depend on the underlying code: hence, some /// member functions are defined in colvarproxy_xxx.h. class colvarmodule::atom { protected: /// \brief Index in the list of atoms involved by the colvars (\b /// NOT in the global topology!) int index; public: /// Internal identifier (zero-based) int id; /// Mass cvm::real mass; /// \brief Current position (copied from the program, can be /// manipulated) cvm::atom_pos pos; /// \brief Current velocity (copied from the program, can be /// manipulated) cvm::rvector vel; /// \brief System force at the previous step (copied from the /// program, can be manipulated) cvm::rvector system_force; /// \brief Gradient of a scalar collective variable with respect /// to this atom /// /// This can only handle a scalar collective variable (i.e. when /// the \link colvarvalue::real_value \endlink member is used /// from the \link colvarvalue \endlink class), which is also the /// most frequent case. For more complex types of \link /// colvarvalue \endlink objects, atomic gradients should be /// defined within the specific \link cvc \endlink /// implementation cvm::rvector grad; /// \brief Default constructor, setting index and id to invalid numbers - atom() : index (-1), id (-1) { reset_data(); } + atom() : index(-1), id(-1) { reset_data(); } /// \brief Initialize an atom for collective variable calculation /// and get its internal identifier \param atom_number Atom index in /// the system topology (starting from 1) - atom (int const &atom_number); + atom(int const &atom_number); /// \brief Initialize an atom for collective variable calculation /// and get its internal identifier \param residue Residue number /// \param atom_name Name of the atom in the residue \param /// segment_id For PSF topologies, the segment identifier; for other /// type of topologies, may not be required - atom (cvm::residue_id const &residue, + atom(cvm::residue_id const &residue, std::string const &atom_name, - std::string const &segment_id = std::string ("")); + std::string const &segment_id = std::string("")); /// Copy constructor - atom (atom const &a); + atom(atom const &a); /// Destructor ~atom(); /// Set non-constant data (everything except id and mass) to zero inline void reset_data() { - pos = atom_pos (0.0); - vel = grad = system_force = rvector (0.0); + pos = atom_pos(0.0); + vel = grad = system_force = rvector(0.0); } /// Get the current position void read_position(); /// Get the current velocity void read_velocity(); /// Get the system force void read_system_force(); /// \brief Apply a force to the atom /// /// The force will be used later by the MD integrator, the /// collective variables module does not integrate equations of /// motion. Multiple calls to this function by either the same /// \link atom \endlink object or different objects with identical /// \link id \endlink, will all add to the existing MD force. - void apply_force (cvm::rvector const &new_force); + void apply_force(cvm::rvector const &new_force); }; /// \brief Group of \link atom \endlink objects, mostly used by a /// \link cvc \endlink /// /// This class inherits from \link colvarparse \endlink and from /// std::vector, and hence all functions and /// operators (including the bracket operator, group[i]) can be used /// on an \link atom_group \endlink object. It can be initialized as /// a vector, or by parsing a keyword in the configuration. class colvarmodule::atom_group : public std::vector, public colvarparse { public: // Note: all members here are kept public, to allow any // object accessing and manipulating them /// \brief If this option is on, this group merely acts as a wrapper /// for a fixed position; any calls to atoms within or to /// functions that return disaggregated data will fail bool b_dummy; /// \brief dummy atom position cvm::atom_pos dummy_atom_pos; /// Sorted list of zero-based (internal) atom ids /// (populated on-demand by create_sorted_ids) std::vector sorted_ids; /// Allocates and populates the sorted list of atom ids - int create_sorted_ids (void); + int create_sorted_ids(void); /// \brief When updating atomic coordinates, translate them to align with the /// center of mass of the reference coordinates bool b_center; /// \brief When updating atom coordinates (and after /// centering them if b_center is set), rotate the group to /// align with the reference coordinates. /// /// Note: gradients will be calculated in the rotated frame: when /// forces will be applied, they will rotated back to the original /// frame bool b_rotate; /// The rotation calculated automatically if b_rotate is defined cvm::rotation rot; /// \brief Indicates that the user has explicitly set centerReference or /// rotateReference, and the corresponding reference: /// cvc's (eg rmsd, eigenvector) will not override the user's choice bool b_user_defined_fit; /// \brief Whether or not the derivatives of the roto-translation /// should be included when calculating the colvar's gradients (default: no) bool b_fit_gradients; /// \brief use reference coordinates for b_center or b_rotate std::vector ref_pos; /// \brief Center of geometry of the reference coordinates; regardless /// of whether b_center is true, ref_pos is centered to zero at /// initialization, and ref_pos_cog serves to center the positions cvm::atom_pos ref_pos_cog; /// \brief If b_center or b_rotate is true, use this group to /// define the transformation (default: this group itself) atom_group *ref_pos_group; /// Total mass of the atom group cvm::real total_mass; /// \brief Don't apply any force on this group (use its coordinates /// only to calculate a colvar) bool noforce; /// \brief Initialize the group by looking up its configuration /// string in conf and parsing it; this is actually done by parse(), /// which is a member function so that a group can be initialized /// also after construction - atom_group (std::string const &conf, + atom_group(std::string const &conf, char const *key); /// \brief Initialize the group by looking up its configuration /// string in conf and parsing it - int parse (std::string const &conf, + int parse(std::string const &conf, char const *key); /// \brief Initialize the group after a temporary vector of atoms - atom_group (std::vector const &atoms); + atom_group(std::vector const &atoms); /// \brief Add an atom to this group - void add_atom (cvm::atom const &a); + void add_atom(cvm::atom const &a); /// \brief Re-initialize the total mass of a group. /// This is needed in case the hosting MD code has an option to /// change atom masses after their initialization. - void reset_mass (std::string &name, int i, int j); + void reset_mass(std::string &name, int i, int j); /// \brief Default constructor atom_group(); /// \brief Destructor ~atom_group(); /// \brief Get the current positions; if b_center or b_rotate are /// true, calc_apply_roto_translation() will be called too void read_positions(); /// \brief (Re)calculate the optimal roto-translation void calc_apply_roto_translation(); /// \brief Save center of geometry fo ref positions, /// then subtract it void center_ref_pos(); /// \brief Move all positions - void apply_translation (cvm::rvector const &t); + void apply_translation(cvm::rvector const &t); /// \brief Rotate all positions - void apply_rotation (cvm::rotation const &q); + void apply_rotation(cvm::rotation const &q); /// \brief Get the current velocities; this must be called always /// *after* read_positions(); if b_rotate is defined, the same /// rotation applied to the coordinates will be used void read_velocities(); /// \brief Get the current system_forces; this must be called always /// *after* read_positions(); if b_rotate is defined, the same /// rotation applied to the coordinates will be used void read_system_forces(); /// Call reset_data() for each atom inline void reset_atoms_data() { for (cvm::atom_iter ai = this->begin(); ai != this->end(); ai++) ai->reset_data(); if (ref_pos_group) ref_pos_group->reset_atoms_data(); } /// \brief Return a copy of the current atom positions std::vector positions() const; /// \brief Return a copy of the current atom positions, shifted by a constant vector - std::vector positions_shifted (cvm::rvector const &shift) const; + std::vector positions_shifted(cvm::rvector const &shift) const; /// \brief Return the center of geometry of the positions, assuming /// that coordinates are already pbc-wrapped cvm::atom_pos center_of_geometry() const; /// \brief Return the center of mass of the positions, assuming that /// coordinates are already pbc-wrapped cvm::atom_pos center_of_mass() const; /// \brief Atom positions at the previous step std::vector old_pos; /// \brief Return a copy of the current atom velocities std::vector velocities() const; /// \brief Return a copy of the system forces std::vector system_forces() const; /// \brief Return a copy of the aggregated total force on the group cvm::rvector system_force() const; /// \brief Shorthand: save the specified gradient on each atom, /// weighting with the atom mass (mostly used in combination with /// \link center_of_mass() \endlink) - void set_weighted_gradient (cvm::rvector const &grad); + void set_weighted_gradient(cvm::rvector const &grad); /// \brief Calculate the derivatives of the fitting transformation void calc_fit_gradients(); /// \brief Derivatives of the fitting transformation std::vector fit_gradients; /// \brief Used by a (scalar) colvar to apply its force on its \link /// atom_group \endlink members /// /// The (scalar) force is multiplied by the colvar gradient for each /// atom; this should be used when a colvar with scalar \link /// colvarvalue \endlink type is used (this is the most frequent /// case: for colvars with a non-scalar type, the most convenient /// solution is to sum together the Cartesian forces from all the /// colvar components, and use apply_force() or apply_forces()). If /// the group is being rotated to a reference frame (e.g. to express /// the colvar independently from the solute rotation), the /// gradients are temporarily rotated to the original frame. - void apply_colvar_force (cvm::real const &force); + void apply_colvar_force(cvm::real const &force); /// \brief Apply a force "to the center of mass", i.e. the force is /// distributed on each atom according to its mass /// /// If the group is being rotated to a reference frame (e.g. to /// express the colvar independently from the solute rotation), the /// force is rotated back to the original frame. Colvar gradients /// are not used, either because they were not defined (e.g because /// the colvar has not a scalar value) or the biases require to /// micromanage the force. - void apply_force (cvm::rvector const &force); + void apply_force(cvm::rvector const &force); /// \brief Apply an array of forces directly on the individual /// atoms; the length of the specified vector must be the same of /// this \link atom_group \endlink. /// /// If the group is being rotated to a reference frame (e.g. to /// express the colvar independently from the solute rotation), the /// forces are rotated back to the original frame. Colvar gradients /// are not used, either because they were not defined (e.g because /// the colvar has not a scalar value) or the biases require to /// micromanage the forces. - void apply_forces (std::vector const &forces); + void apply_forces(std::vector const &forces); }; #endif diff --git a/lib/colvars/colvarbias.cpp b/lib/colvars/colvarbias.cpp index 7c21c551c..8f1d85b24 100644 --- a/lib/colvars/colvarbias.cpp +++ b/lib/colvars/colvarbias.cpp @@ -1,162 +1,167 @@ /// -*- c++ -*- #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarbias.h" -colvarbias::colvarbias (std::string const &conf, char const *key) - : colvarparse(), has_data (false) +colvarbias::colvarbias(std::string const &conf, char const *key) + : colvarparse(), has_data(false) { - cvm::log ("Initializing a new \""+std::string (key)+"\" instance.\n"); + cvm::log("Initializing a new \""+std::string(key)+"\" instance.\n"); size_t rank = 1; - std::string const key_str (key); + std::string const key_str(key); - if (to_lower_cppstr (key_str) == std::string ("abf")) { + if (to_lower_cppstr(key_str) == std::string("abf")) { rank = cvm::n_abf_biases+1; } - if (to_lower_cppstr (key_str) == std::string ("harmonic") || - to_lower_cppstr (key_str) == std::string ("linear")) { + if (to_lower_cppstr(key_str) == std::string("harmonic") || + to_lower_cppstr(key_str) == std::string("linear")) { rank = cvm::n_rest_biases+1; } - if (to_lower_cppstr (key_str) == std::string ("histogram")) { + if (to_lower_cppstr(key_str) == std::string("histogram")) { rank = cvm::n_histo_biases+1; } - if (to_lower_cppstr (key_str) == std::string ("metadynamics")) { + if (to_lower_cppstr(key_str) == std::string("metadynamics")) { rank = cvm::n_meta_biases+1; } - get_keyval (conf, "name", name, key_str+cvm::to_str (rank)); + get_keyval(conf, "name", name, key_str+cvm::to_str(rank)); - if (cvm::bias_by_name (this->name) != NULL) { - cvm::error ("Error: this bias cannot have the same name, \""+this->name+ + if (cvm::bias_by_name(this->name) != NULL) { + cvm::error("Error: this bias cannot have the same name, \""+this->name+ "\", as another bias.\n", INPUT_ERROR); return; } // lookup the associated colvars std::vector colvars_str; - if (get_keyval (conf, "colvars", colvars_str)) { + if (get_keyval(conf, "colvars", colvars_str)) { for (size_t i = 0; i < colvars_str.size(); i++) { - add_colvar (colvars_str[i]); + add_colvar(colvars_str[i]); } } if (!colvars.size()) { - cvm::error ("Error: no collective variables specified.\n"); + cvm::error("Error: no collective variables specified.\n"); return; } - get_keyval (conf, "outputEnergy", b_output_energy, false); + get_keyval(conf, "outputEnergy", b_output_energy, false); } colvarbias::colvarbias() - : colvarparse(), has_data (false) + : colvarparse(), has_data(false) {} colvarbias::~colvarbias() { // Remove references to this bias from colvars for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); ++cvi) { for (std::vector::iterator bi = (*cvi)->biases.begin(); bi != (*cvi)->biases.end(); ++bi) { if ( *bi == this) { - (*cvi)->biases.erase (bi); + (*cvi)->biases.erase(bi); break; } } } // ...and from the colvars module for (std::vector::iterator bi = cvm::biases.begin(); bi != cvm::biases.end(); ++bi) { if ( *bi == this) { - cvm::biases.erase (bi); + cvm::biases.erase(bi); break; } } } -void colvarbias::add_colvar (std::string const &cv_name) +void colvarbias::add_colvar(std::string const &cv_name) { - if (colvar *cvp = cvm::colvar_by_name (cv_name)) { - cvp->enable (colvar::task_gradients); + if (colvar *cv = cvm::colvar_by_name(cv_name)) { + cv->enable(colvar::task_gradients); if (cvm::debug()) - cvm::log ("Applying this bias to collective variable \""+ - cvp->name+"\".\n"); - colvars.push_back (cvp); - colvar_forces.push_back (colvarvalue (cvp->type())); - cvp->biases.push_back (this); // add back-reference to this bias to colvar + cvm::log("Applying this bias to collective variable \""+ + cv->name+"\".\n"); + colvars.push_back(cv); + colvar_forces.push_back(colvarvalue()); + colvar_forces.back().type(cv->value()); // make sure each forces is initialized to zero + colvar_forces.back().reset(); + cv->biases.push_back(this); // add back-reference to this bias to colvar } else { - cvm::error ("Error: cannot find a colvar named \""+ - cv_name+"\".\n"); + cvm::error("Error: cannot find a colvar named \""+ + cv_name+"\".\n"); } } void colvarbias::communicate_forces() { for (size_t i = 0; i < colvars.size(); i++) { if (cvm::debug()) { - cvm::log ("Communicating a force to colvar \""+ - colvars[i]->name+"\", of type \""+ - colvarvalue::type_desc[colvars[i]->type()]+"\".\n"); + cvm::log("Communicating a force to colvar \""+ + colvars[i]->name+"\".\n"); } - colvars[i]->add_bias_force (colvar_forces[i]); + colvars[i]->add_bias_force(colvar_forces[i]); } } void colvarbias::change_configuration(std::string const &conf) { - cvm::error ("Error: change_configuration() not implemented.\n"); + cvm::error("Error: change_configuration() not implemented.\n"); } cvm::real colvarbias::energy_difference(std::string const &conf) { - cvm::error ("Error: energy_difference() not implemented.\n"); + cvm::error("Error: energy_difference() not implemented.\n"); return 0.; } // So far, these are only implemented in colvarsbias_abf int colvarbias::bin_num() { - cvm::error ("Error: bin_num() not implemented.\n"); - return -1; + cvm::error("Error: bin_num() not implemented.\n"); + return COLVARS_NOT_IMPLEMENTED; } int colvarbias::current_bin() { - cvm::error ("Error: current_bin() not implemented.\n"); - return -1; + cvm::error("Error: current_bin() not implemented.\n"); + return COLVARS_NOT_IMPLEMENTED; } int colvarbias::bin_count(int bin_index) { - cvm::error ("Error: bin_count() not implemented.\n"); - return -1; + cvm::error("Error: bin_count() not implemented.\n"); + return COLVARS_NOT_IMPLEMENTED; +} +int colvarbias::replica_share() +{ + cvm::error("Error: replica_share() not implemented.\n"); + return COLVARS_NOT_IMPLEMENTED; } - -std::ostream & colvarbias::write_traj_label (std::ostream &os) +std::ostream & colvarbias::write_traj_label(std::ostream &os) { os << " "; if (b_output_energy) os << " E_" - << cvm::wrap_string (this->name, cvm::en_width-2); + << cvm::wrap_string(this->name, cvm::en_width-2); return os; } -std::ostream & colvarbias::write_traj (std::ostream &os) +std::ostream & colvarbias::write_traj(std::ostream &os) { os << " "; if (b_output_energy) os << " " << bias_energy; return os; } diff --git a/lib/colvars/colvarbias.h b/lib/colvars/colvarbias.h index ad24f40f3..03674cc1f 100644 --- a/lib/colvars/colvarbias.h +++ b/lib/colvars/colvarbias.h @@ -1,96 +1,96 @@ /// -*- c++ -*- #ifndef COLVARBIAS_H #define COLVARBIAS_H #include "colvar.h" #include "colvarparse.h" /// \brief Collective variable bias, base class class colvarbias : public colvarparse { public: /// Name of this bias std::string name; /// Add a new collective variable to this bias - void add_colvar (std::string const &cv_name); + void add_colvar(std::string const &cv_name); /// Retrieve colvar values and calculate their biasing forces /// Return bias energy virtual cvm::real update() = 0; // TODO: move update_bias here (share with metadynamics) /// Load new configuration - force constant and/or centers only virtual void change_configuration(std::string const &conf); /// 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); + virtual int bin_count(int bin_index); //// Share information between replicas, whatever it may be. - virtual void replica_share() {}; + virtual int replica_share(); /// Perform analysis tasks virtual inline void analyse() {} /// Send forces to the collective variables void communicate_forces(); /// \brief Constructor /// /// The constructor of the colvarbias base class is protected, so /// that it can only be called from inherited classes - colvarbias (std::string const &conf, char const *key); + colvarbias(std::string const &conf, char const *key); /// Default constructor colvarbias(); /// Destructor virtual ~colvarbias(); /// Read the bias configuration from a restart file - virtual std::istream & read_restart (std::istream &is) = 0; + virtual std::istream & read_restart(std::istream &is) = 0; /// Write the bias configuration to a restart file - virtual std::ostream & write_restart (std::ostream &os) = 0; + virtual std::ostream & write_restart(std::ostream &os) = 0; /// Write a label to the trajectory file (comment line) - virtual std::ostream & write_traj_label (std::ostream &os); + virtual std::ostream & write_traj_label(std::ostream &os); /// Output quantities such as the bias energy to the trajectory file - virtual std::ostream & write_traj (std::ostream &os); + virtual std::ostream & write_traj(std::ostream &os); - inline cvm::real get_energy () { + inline cvm::real get_energy() { return bias_energy; } protected: /// \brief Pointers to collective variables to which the bias is /// applied; current values and metric functions will be obtained /// through each colvar object std::vector colvars; /// \brief Current forces from this bias to the colvars std::vector colvar_forces; /// \brief Current energy of this bias (colvar_forces should be obtained by deriving this) cvm::real bias_energy; /// Whether to write the current bias energy from this bias to the trajectory file bool b_output_energy; /// \brief Whether this bias has already accumulated information /// (when relevant) bool has_data; }; #endif diff --git a/lib/colvars/colvarbias_abf.cpp b/lib/colvars/colvarbias_abf.cpp index 812490013..543be6a95 100644 --- a/lib/colvars/colvarbias_abf.cpp +++ b/lib/colvars/colvarbias_abf.cpp @@ -1,675 +1,682 @@ /// -*- c++ -*- /******************************************************************************** * Implementation of the ABF and histogram biases * ********************************************************************************/ #include "colvarmodule.h" #include "colvar.h" #include "colvarbias_abf.h" /// ABF bias constructor; parses the config file -colvarbias_abf::colvarbias_abf (std::string const &conf, char const *key) - : colvarbias (conf, key), - gradients (NULL), - samples (NULL) +colvarbias_abf::colvarbias_abf(std::string const &conf, char const *key) + : colvarbias(conf, key), + gradients(NULL), + samples(NULL) { // TODO relax this in case of VMD plugin if (cvm::temperature() == 0.0) - cvm::log ("WARNING: ABF should not be run without a thermostat or at 0 Kelvin!\n"); + cvm::log("WARNING: ABF should not be run without a thermostat or at 0 Kelvin!\n"); // ************* parsing general ABF options *********************** - get_keyval (conf, "applyBias", apply_bias, true); - if (!apply_bias) cvm::log ("WARNING: ABF biases will *not* be applied!\n"); + get_keyval(conf, "applyBias", apply_bias, true); + if (!apply_bias) cvm::log("WARNING: ABF biases will *not* be applied!\n"); - get_keyval (conf, "updateBias", update_bias, true); - if (!update_bias) cvm::log ("WARNING: ABF biases will *not* be updated!\n"); + get_keyval(conf, "updateBias", update_bias, true); + if (!update_bias) cvm::log("WARNING: ABF biases will *not* be updated!\n"); - get_keyval (conf, "hideJacobian", hide_Jacobian, false); + get_keyval(conf, "hideJacobian", hide_Jacobian, false); if (hide_Jacobian) { - cvm::log ("Jacobian (geometric) forces will be handled internally.\n"); + cvm::log("Jacobian (geometric) forces will be handled internally.\n"); } else { - cvm::log ("Jacobian (geometric) forces will be included in reported free energy gradients.\n"); + cvm::log("Jacobian (geometric) forces will be included in reported free energy gradients.\n"); } - get_keyval (conf, "fullSamples", full_samples, 200); + get_keyval(conf, "fullSamples", full_samples, 200); if ( full_samples <= 1 ) full_samples = 1; min_samples = full_samples / 2; // full_samples - min_samples >= 1 is guaranteed - get_keyval (conf, "inputPrefix", input_prefix, std::vector ()); - get_keyval (conf, "outputFreq", output_freq, cvm::restart_out_freq); - get_keyval (conf, "historyFreq", history_freq, 0); + get_keyval(conf, "inputPrefix", input_prefix, std::vector ()); + get_keyval(conf, "outputFreq", output_freq, cvm::restart_out_freq); + get_keyval(conf, "historyFreq", history_freq, 0); b_history_files = (history_freq > 0); // shared ABF - get_keyval (conf, "shared", shared_on, false); + 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."); + 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"); + 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); + get_keyval(conf, "sharedFreq", shared_freq, output_freq); } // ************* checking the associated colvars ******************* if (colvars.size() == 0) { - cvm::error ("Error: no collective variables specified for the ABF bias.\n"); + cvm::error("Error: no collective variables specified for the ABF bias.\n"); } for (size_t i = 0; i < colvars.size(); i++) { - if (colvars[i]->type() != colvarvalue::type_scalar) { - cvm::error ("Error: ABF bias can only use scalar-type variables.\n"); + if (colvars[i]->value().type() != colvarvalue::type_scalar) { + cvm::error("Error: ABF bias can only use scalar-type variables.\n"); } - colvars[i]->enable (colvar::task_gradients); + colvars[i]->enable(colvar::task_gradients); if (update_bias) { // Request calculation of system force (which also checks for availability) - colvars[i]->enable (colvar::task_system_force); + colvars[i]->enable(colvar::task_system_force); if (!colvars[i]->tasks[colvar::task_extended_lagrangian]) { // request computation of Jacobian force - colvars[i]->enable (colvar::task_Jacobian_force); + colvars[i]->enable(colvar::task_Jacobian_force); // request Jacobian force as part as system force // except if the user explicitly requires the "silent" Jacobian // correction AND the colvar has a single component if (hide_Jacobian) { if (colvars[i]->n_components() > 1) { - cvm::log ("WARNING: colvar \"" + colvars[i]->name + cvm::log("WARNING: colvar \"" + colvars[i]->name + "\" has multiple components; reporting its Jacobian forces\n"); - colvars[i]->enable (colvar::task_report_Jacobian_force); + colvars[i]->enable(colvar::task_report_Jacobian_force); } } else { - colvars[i]->enable (colvar::task_report_Jacobian_force); + colvars[i]->enable(colvar::task_report_Jacobian_force); } } } // Here we could check for orthogonality of the Cartesian coordinates // and make it just a warning if some parameter is set? } - if (get_keyval (conf, "maxForce", max_force)) { + if (get_keyval(conf, "maxForce", max_force)) { if (max_force.size() != colvars.size()) { - cvm::error ("Error: Number of parameters to maxForce does not match number of colvars."); + cvm::error("Error: Number of parameters to maxForce does not match number of colvars."); } for (size_t i=0; isamples = 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 = 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 (); + read_gradients_samples(); } - cvm::log ("Finished ABF setup.\n"); + cvm::log("Finished ABF setup.\n"); } /// Destructor colvarbias_abf::~colvarbias_abf() { if (samples) { delete samples; samples = NULL; } if (gradients) { delete gradients; 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) cvm::n_abf_biases -= 1; } /// Update the FE gradient, compute and apply biasing force /// also output data to disk if needed cvm::real colvarbias_abf::update() { - if (cvm::debug()) cvm::log ("Updating ABF bias " + this->name); + if (cvm::debug()) cvm::log("Updating ABF bias " + this->name); if (cvm::step_relative() == 0) { // At first timestep, do only: // initialization stuff (file operations relying on n_abf_biases // compute current value of colvars if ( cvm::n_abf_biases == 1 && cvm::n_meta_biases == 0 ) { // This is the only ABF bias output_prefix = cvm::output_prefix; } else { output_prefix = cvm::output_prefix + "." + this->name; } for (size_t i=0; icurrent_bin_scalar(i); } } else { for (size_t i=0; icurrent_bin_scalar(i); } - if ( update_bias && samples->index_ok (force_bin) ) { + if ( update_bias && samples->index_ok(force_bin) ) { // Only if requested and within bounds of the grid... - for (size_t i=0; isystem_force(); } - gradients->acc_force (force_bin, force); + gradients->acc_force(force_bin, force); } } // save bin for next timestep force_bin = bin; // Reset biasing forces from previous timestep for (size_t i=0; iindex_ok (bin) ) { + if ( apply_bias && samples->index_ok(bin) ) { - size_t count = samples->value (bin); + size_t count = samples->value(bin); cvm::real fact = 1.0; // Factor that ensures smooth introduction of the force if ( count < full_samples ) { fact = ( count < min_samples) ? 0.0 : - (cvm::real (count - min_samples)) / (cvm::real (full_samples - min_samples)); + (cvm::real(count - min_samples)) / (cvm::real(full_samples - min_samples)); } - const cvm::real * grad = &(gradients->value (bin)); + const cvm::real * grad = &(gradients->value(bin)); if ( fact != 0.0 ) { if ( (colvars.size() == 1) && colvars[0]->periodic_boundaries() ) { // Enforce a zero-mean bias on periodic, 1D coordinates // in other words: boundary condition is that the biasing potential is periodic - colvar_forces[0].real_value = fact * (grad[0] / cvm::real (count) - gradients->average ()); + colvar_forces[0].real_value = fact * (grad[0] / cvm::real(count) - gradients->average()); } else { for (size_t i=0; i max_force[i] * max_force[i] ) { colvar_forces[i].real_value = (colvar_forces[i].real_value > 0 ? max_force[i] : -1.0 * max_force[i]); } } } } } if (output_freq && (cvm::step_absolute() % output_freq) == 0) { - if (cvm::debug()) cvm::log ("ABF bias trying to write gradients and samples to disk"); - write_gradients_samples (output_prefix); + if (cvm::debug()) cvm::log("ABF bias trying to write gradients and samples to disk"); + write_gradients_samples(output_prefix); } if (b_history_files && (cvm::step_absolute() % history_freq) == 0) { - cvm::log ("ABFHISTORYFILE "+cvm::to_str(cvm::step_absolute())); + 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)); + 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())+"."); + cvm::log("Prepared sample and gradient buffers at step "+cvm::to_str(cvm::step_absolute())+"."); } return 0.0; } -void colvarbias_abf::replica_share () { +int colvarbias_abf::replica_share() { int p; - if( !cvm::replica_enabled() ) { - cvm::error ("Error: shared ABF: No replicas.\n"); - return; + if ( !cvm::replica_enabled() ) { + cvm::error("Error: shared ABF: No replicas.\n"); + return COLVARS_ERROR; } // 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; + cvm::error("Error: shared ABF: Tried to apply shared ABF before any sampling had occurred.\n"); + return COLVARS_ERROR; } // Share gradients for shared ABF. - cvm::log ("shared ABF: Sharing gradient and samples among replicas at step "+cvm::to_str(cvm::step_absolute()) ); + 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); + 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(); + + return COLVARS_OK; } -void colvarbias_abf::write_gradients_samples (const std::string &prefix, bool append) +void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool append) { std::string samples_out_name = prefix + ".count"; std::string gradients_out_name = prefix + ".grad"; std::ios::openmode mode = (append ? std::ios::app : std::ios::out); std::ofstream samples_os; std::ofstream gradients_os; - if (!append) cvm::backup_file (samples_out_name.c_str()); - samples_os.open (samples_out_name.c_str(), mode); - if (!samples_os.good()) cvm::error ("Error opening ABF samples file " + samples_out_name + " for writing"); - samples->write_multicol (samples_os); - samples_os.close (); + if (!append) cvm::backup_file(samples_out_name.c_str()); + samples_os.open(samples_out_name.c_str(), mode); + if (!samples_os.good()) cvm::error("Error opening ABF samples file " + samples_out_name + " for writing"); + samples->write_multicol(samples_os); + samples_os.close(); - if (!append) cvm::backup_file (gradients_out_name.c_str()); - gradients_os.open (gradients_out_name.c_str(), mode); - if (!gradients_os.good()) cvm::error ("Error opening ABF gradient file " + gradients_out_name + " for writing"); - gradients->write_multicol (gradients_os); - gradients_os.close (); + if (!append) cvm::backup_file(gradients_out_name.c_str()); + gradients_os.open(gradients_out_name.c_str(), mode); + if (!gradients_os.good()) cvm::error("Error opening ABF gradient file " + gradients_out_name + " for writing"); + gradients->write_multicol(gradients_os); + gradients_os.close(); - if (colvars.size () == 1) { + if (colvars.size() == 1) { std::string pmf_out_name = prefix + ".pmf"; - if (!append) cvm::backup_file (pmf_out_name.c_str()); + if (!append) cvm::backup_file(pmf_out_name.c_str()); std::ofstream pmf_os; // Do numerical integration and output a PMF - pmf_os.open (pmf_out_name.c_str(), mode); - if (!pmf_os.good()) cvm::error ("Error opening pmf file " + pmf_out_name + " for writing"); - gradients->write_1D_integral (pmf_os); + pmf_os.open(pmf_out_name.c_str(), mode); + if (!pmf_os.good()) cvm::error("Error opening pmf file " + pmf_out_name + " for writing"); + gradients->write_1D_integral(pmf_os); pmf_os << std::endl; - pmf_os.close (); + pmf_os.close(); } 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)); + cvm::error("Error: Tried to get bin count from invalid bin index "+cvm::to_str(bin_index)); return -1; } std::vector ix(1,(int)bin_index); return samples->value(ix); } -void colvarbias_abf::read_gradients_samples () +void colvarbias_abf::read_gradients_samples() { std::string samples_in_name, gradients_in_name; for ( size_t i = 0; i < input_prefix.size(); i++ ) { samples_in_name = input_prefix[i] + ".count"; gradients_in_name = input_prefix[i] + ".grad"; // For user-provided files, the per-bias naming scheme may not apply std::ifstream is; - cvm::log ("Reading sample count from " + samples_in_name + " and gradients from " + gradients_in_name); - is.open (samples_in_name.c_str()); - if (!is.good()) cvm::error ("Error opening ABF samples file " + samples_in_name + " for reading"); - samples->read_multicol (is, true); - is.close (); + cvm::log("Reading sample count from " + samples_in_name + " and gradients from " + gradients_in_name); + is.open(samples_in_name.c_str()); + if (!is.good()) cvm::error("Error opening ABF samples file " + samples_in_name + " for reading"); + samples->read_multicol(is, true); + is.close(); is.clear(); - is.open (gradients_in_name.c_str()); - if (!is.good()) cvm::error ("Error opening ABF gradient file " + gradients_in_name + " for reading"); - gradients->read_multicol (is, true); - is.close (); + is.open(gradients_in_name.c_str()); + if (!is.good()) cvm::error("Error opening ABF gradient file " + gradients_in_name + " for reading"); + gradients->read_multicol(is, true); + is.close(); } return; } -std::ostream & colvarbias_abf::write_restart (std::ostream& os) +std::ostream & colvarbias_abf::write_restart(std::ostream& os) { - std::ios::fmtflags flags (os.flags ()); - os.setf(std::ios::fmtflags (0), std::ios::floatfield); // default floating-point format + std::ios::fmtflags flags(os.flags()); + os.setf(std::ios::fmtflags(0), std::ios::floatfield); // default floating-point format os << "abf {\n" << " configuration {\n" << " name " << this->name << "\n"; os << " }\n"; os << "samples\n"; - samples->write_raw (os, 8); + samples->write_raw(os, 8); os << "\ngradient\n"; - gradients->write_raw (os); + gradients->write_raw(os); os << "}\n\n"; - os.flags (flags); + os.flags(flags); return os; } -std::istream & colvarbias_abf::read_restart (std::istream& is) +std::istream & colvarbias_abf::read_restart(std::istream& is) { if ( input_prefix.size() > 0 ) { - cvm::error ("ERROR: cannot provide both inputPrefix and restart information (colvarsInput)"); + cvm::error("ERROR: cannot provide both inputPrefix and restart information(colvarsInput)"); } size_t const start_pos = is.tellg(); - cvm::log ("Restarting ABF bias \""+ + cvm::log("Restarting ABF bias \""+ this->name+"\".\n"); std::string key, brace, conf; if ( !(is >> key) || !(key == "abf") || !(is >> brace) || !(brace == "{") || - !(is >> colvarparse::read_block ("configuration", conf)) ) { - cvm::log ("Error: in reading restart configuration for ABF bias \""+ + !(is >> colvarparse::read_block("configuration", conf)) ) { + cvm::log("Error: in reading restart configuration for ABF bias \""+ this->name+"\" at position "+ - cvm::to_str (is.tellg())+" in stream.\n"); + cvm::to_str(is.tellg())+" in stream.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } std::string name = ""; - if ( (colvarparse::get_keyval (conf, "name", name, std::string (""), colvarparse::parse_silent)) && + if ( (colvarparse::get_keyval(conf, "name", name, std::string(""), colvarparse::parse_silent)) && (name != this->name) ) - cvm::error ("Error: in the restart file, the " - "\"abf\" block has wrong name (" + name + ")\n"); + cvm::error("Error: in the restart file, the " + "\"abf\" block has wrong name(" + name + ")\n"); if ( name == "" ) { - cvm::error ("Error: \"abf\" block in the restart file has no name.\n"); + cvm::error("Error: \"abf\" block in the restart file has no name.\n"); } if ( !(is >> key) || !(key == "samples")) { - cvm::log ("Error: in reading restart configuration for ABF bias \""+ + cvm::log("Error: in reading restart configuration for ABF bias \""+ this->name+"\" at position "+ - cvm::to_str (is.tellg())+" in stream.\n"); + cvm::to_str(is.tellg())+" in stream.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } - if (! samples->read_raw (is)) { + if (! samples->read_raw(is)) { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } if ( !(is >> key) || !(key == "gradient")) { - cvm::log ("Error: in reading restart configuration for ABF bias \""+ + cvm::log("Error: in reading restart configuration for ABF bias \""+ this->name+"\" at position "+ - cvm::to_str (is.tellg())+" in stream.\n"); + cvm::to_str(is.tellg())+" in stream.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } - if (! gradients->read_raw (is)) { + if (! gradients->read_raw(is)) { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } is >> brace; if (brace != "}") { - cvm::error ("Error: corrupt restart information for ABF bias \""+ + cvm::error("Error: corrupt restart information for ABF bias \""+ this->name+"\": no matching brace at position "+ - cvm::to_str (is.tellg())+" in the restart file.\n"); - is.setstate (std::ios::failbit); + cvm::to_str(is.tellg())+" in the restart file.\n"); + is.setstate(std::ios::failbit); } return is; } /// Histogram "bias" constructor -colvarbias_histogram::colvarbias_histogram (std::string const &conf, char const *key) - : colvarbias (conf, key), - grid (NULL) +colvarbias_histogram::colvarbias_histogram(std::string const &conf, char const *key) + : colvarbias(conf, key), + grid(NULL), out_name("") { - get_keyval (conf, "outputfreq", output_freq, cvm::restart_out_freq); + get_keyval(conf, "outputfreq", output_freq, cvm::restart_out_freq); if ( output_freq == 0 ) { - cvm::error ("User required histogram with zero output frequency"); + cvm::error("User required histogram with zero output frequency"); } grid = new colvar_grid_count (colvars); - bin.assign (colvars.size(), 0); - - out_name = cvm::output_prefix + "." + this->name + ".dat"; - cvm::log ("Histogram will be written to file " + out_name); + bin.assign(colvars.size(), 0); - cvm::log ("Finished histogram setup.\n"); + cvm::log("Finished histogram setup.\n"); } /// Destructor colvarbias_histogram::~colvarbias_histogram() { if (grid_os.good()) grid_os.close(); if (grid) { delete grid; grid = NULL; } if (cvm::n_histo_biases > 0) cvm::n_histo_biases -= 1; } /// Update the grid cvm::real colvarbias_histogram::update() { - if (cvm::debug()) cvm::log ("Updating Grid bias " + this->name); + if (cvm::debug()) cvm::log("Updating Grid bias " + this->name); + + // At the first timestep, we need to assign out_name since + // output_prefix is unset during the constructor + + if (cvm::step_relative() == 0) { + out_name = cvm::output_prefix + "." + this->name + ".dat"; + cvm::log("Histogram " + this->name + " will be written to file \"" + out_name + "\""); + } for (size_t i=0; icurrent_bin_scalar(i); } - if ( grid->index_ok (bin) ) { // Only within bounds of the grid... - grid->incr_count (bin); + if ( grid->index_ok(bin) ) { // Only within bounds of the grid... + grid->incr_count(bin); } if (output_freq && (cvm::step_absolute() % output_freq) == 0) { - if (cvm::debug()) cvm::log ("Histogram bias trying to write grid to disk"); + if (cvm::debug()) cvm::log("Histogram bias trying to write grid to disk"); - grid_os.open (out_name.c_str()); - if (!grid_os.good()) cvm::error ("Error opening histogram file " + out_name + " for writing"); - grid->write_multicol (grid_os); - grid_os.close (); + grid_os.open(out_name.c_str()); + if (!grid_os.good()) cvm::error("Error opening histogram file " + out_name + " for writing"); + grid->write_multicol(grid_os); + grid_os.close(); } return 0.0; // no bias energy for histogram } -std::istream & colvarbias_histogram::read_restart (std::istream& is) +std::istream & colvarbias_histogram::read_restart(std::istream& is) { size_t const start_pos = is.tellg(); - cvm::log ("Restarting collective variable histogram \""+ + cvm::log("Restarting collective variable histogram \""+ this->name+"\".\n"); std::string key, brace, conf; if ( !(is >> key) || !(key == "histogram") || !(is >> brace) || !(brace == "{") || - !(is >> colvarparse::read_block ("configuration", conf)) ) { - cvm::log ("Error: in reading restart configuration for histogram \""+ + !(is >> colvarparse::read_block("configuration", conf)) ) { + cvm::log("Error: in reading restart configuration for histogram \""+ this->name+"\" at position "+ - cvm::to_str (is.tellg())+" in stream.\n"); + cvm::to_str(is.tellg())+" in stream.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } int id = -1; std::string name = ""; - if ( (colvarparse::get_keyval (conf, "name", name, std::string (""), colvarparse::parse_silent)) && + if ( (colvarparse::get_keyval(conf, "name", name, std::string(""), colvarparse::parse_silent)) && (name != this->name) ) - cvm::error ("Error: in the restart file, the " + cvm::error("Error: in the restart file, the " "\"histogram\" block has a wrong name: different system?\n"); if ( (id == -1) && (name == "") ) { - cvm::error ("Error: \"histogram\" block in the restart file " + cvm::error("Error: \"histogram\" block in the restart file " "has no name.\n"); } if ( !(is >> key) || !(key == "grid")) { - cvm::error ("Error: in reading restart configuration for histogram \""+ + cvm::error("Error: in reading restart configuration for histogram \""+ this->name+"\" at position "+ - cvm::to_str (is.tellg())+" in stream.\n"); + cvm::to_str(is.tellg())+" in stream.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } - if (! grid->read_raw (is)) { + if (! grid->read_raw(is)) { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } is >> brace; if (brace != "}") { - cvm::error ("Error: corrupt restart information for ABF bias \""+ + cvm::error("Error: corrupt restart information for ABF bias \""+ this->name+"\": no matching brace at position "+ - cvm::to_str (is.tellg())+" in the restart file.\n"); - is.setstate (std::ios::failbit); + cvm::to_str(is.tellg())+" in the restart file.\n"); + is.setstate(std::ios::failbit); } return is; } -std::ostream & colvarbias_histogram::write_restart (std::ostream& os) +std::ostream & colvarbias_histogram::write_restart(std::ostream& os) { os << "histogram {\n" << " configuration {\n" << " name " << this->name << "\n"; os << " }\n"; os << "grid\n"; - grid->write_raw (os, 8); + grid->write_raw(os, 8); os << "}\n\n"; return os; } diff --git a/lib/colvars/colvarbias_abf.h b/lib/colvars/colvarbias_abf.h index b89ca68de..f9f6cb702 100644 --- a/lib/colvars/colvarbias_abf.h +++ b/lib/colvars/colvarbias_abf.h @@ -1,118 +1,118 @@ /************************************************************************ * Headers for the ABF and histogram biases * ************************************************************************/ #ifndef COLVARBIAS_ABF_H #define COLVARBIAS_ABF_H #include #include #include #include #include "colvarbias.h" #include "colvargrid.h" typedef cvm::real* gradient_t; /// ABF bias class colvarbias_abf : public colvarbias { public: - colvarbias_abf (std::string const &conf, char const *key); - ~colvarbias_abf (); + colvarbias_abf(std::string const &conf, char const *key); + ~colvarbias_abf(); - cvm::real update (); + cvm::real update(); private: /// Filename prefix for human-readable gradient/sample count output std::string output_prefix; /// Base filename(s) for reading previous gradient data (replaces data from restart file) std::vector input_prefix; bool apply_bias; bool update_bias; bool hide_Jacobian; size_t full_samples; size_t min_samples; /// frequency for updating output files (default: same as restartFreq?) int output_freq; /// Write combined files with a history of all output data? bool b_history_files; size_t history_freq; /// Cap applied biasing force? bool cap_force; std::vector max_force; // Internal data and methods std::vector bin, force_bin; gradient_t force; /// n-dim grid of free energy gradients colvar_grid_gradient *gradients; /// 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(); + virtual int 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); + 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 (); + void read_gradients_samples(); - std::istream& read_restart (std::istream&); - std::ostream& write_restart (std::ostream&); + std::istream& read_restart(std::istream&); + std::ostream& write_restart(std::ostream&); }; /// Histogram "bias" (does as the name says) class colvarbias_histogram : public colvarbias { public: - colvarbias_histogram (std::string const &conf, char const *key); - ~colvarbias_histogram (); + colvarbias_histogram(std::string const &conf, char const *key); + ~colvarbias_histogram(); - cvm::real update (); + cvm::real update(); private: /// n-dim histogram colvar_grid_count *grid; std::vector bin; std::string out_name; int output_freq; - void write_grid (); + void write_grid(); std::ofstream grid_os; /// Stream for writing grid to disk - std::istream& read_restart (std::istream&); - std::ostream& write_restart (std::ostream&); + std::istream& read_restart(std::istream&); + std::ostream& write_restart(std::ostream&); }; #endif diff --git a/lib/colvars/colvarbias_alb.cpp b/lib/colvars/colvarbias_alb.cpp index 867203a8a..78d7341af 100644 --- a/lib/colvars/colvarbias_alb.cpp +++ b/lib/colvars/colvarbias_alb.cpp @@ -1,428 +1,440 @@ +// -*- c++ -*- + +#include +#include +#include + #include "colvarmodule.h" #include "colvarbias_alb.h" #include "colvarbias.h" -#include -#include + +#ifdef _MSC_VER +#if _MSC_VER <= 1700 +#define copysign(A,B) _copysign(A,B) +double fmax(double A, double B) { return ( A > B ? A : B ); } +double fmin(double A, double B) { return ( A < B ? A : B ); } +#endif +#endif /* Note about nomenclature. Force constant is called a coupling * constant here to emphasize its changing in the code. Outwards, * everything is called a force constant to keep it consistent with * the rest of colvars. * */ colvarbias_alb::colvarbias_alb(std::string const &conf, char const *key) : colvarbias(conf, key), update_calls(0), b_equilibration(true) { size_t i; // get the initial restraint centers - colvar_centers.resize (colvars.size()); + colvar_centers.resize(colvars.size()); means.resize(colvars.size()); ssd.resize(colvars.size()); //sum of squares of differences from mean //setup force vectors max_coupling_range.resize(colvars.size()); max_coupling_rate.resize(colvars.size()); coupling_accum.resize(colvars.size()); set_coupling.resize(colvars.size()); current_coupling.resize(colvars.size()); coupling_rate.resize(colvars.size()); for (i = 0; i < colvars.size(); i++) { - colvar_centers[i].type (colvars[i]->type()); + colvar_centers[i].type(colvars[i]->value()); //zero moments means[i] = ssd[i] = 0; //zero force some of the force vectors that aren't initialized coupling_accum[i] = current_coupling[i] = 0; } - if (get_keyval (conf, "centers", colvar_centers, colvar_centers)) { + if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) { for (i = 0; i < colvars.size(); i++) { colvar_centers[i].apply_constraints(); } } else { colvar_centers.clear(); - cvm::fatal_error ("Error: must define the initial centers of adaptive linear bias .\n"); + cvm::fatal_error("Error: must define the initial centers of adaptive linear bias .\n"); } if (colvar_centers.size() != colvars.size()) - cvm::fatal_error ("Error: number of centers does not match " + cvm::fatal_error("Error: number of centers does not match " "that of collective variables.\n"); - if(!get_keyval (conf, "UpdateFrequency", update_freq, 0)) + if (!get_keyval(conf, "UpdateFrequency", update_freq, 0)) cvm::fatal_error("Error: must set updateFrequency for adaptive linear bias.\n"); //we split the time between updating and equilibrating update_freq /= 2; - if(update_freq == 0) + if (update_freq == 0) cvm::fatal_error("Error: must set updateFrequency to greater than 2.\n"); - get_keyval (conf, "outputCenters", b_output_centers, false); - get_keyval (conf, "outputGradient", b_output_grad, false); - get_keyval (conf, "outputCoupling", b_output_coupling, true); - get_keyval (conf, "hardForceRange", b_hard_coupling_range, true); + get_keyval(conf, "outputCenters", b_output_centers, false); + get_keyval(conf, "outputGradient", b_output_grad, false); + get_keyval(conf, "outputCoupling", b_output_coupling, true); + get_keyval(conf, "hardForceRange", b_hard_coupling_range, true); //initial guess - if(!get_keyval (conf, "forceConstant", set_coupling, set_coupling)) - for(i =0 ; i < colvars.size(); i++) + if (!get_keyval(conf, "forceConstant", set_coupling, set_coupling)) + for (i =0 ; i < colvars.size(); i++) set_coupling[i] = 0.; //how we're going to increase to that point - for(i = 0; i < colvars.size(); i++) + for (i = 0; i < colvars.size(); i++) coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq; - if(!get_keyval (conf, "forceRange", max_coupling_range, max_coupling_range)) { + if (!get_keyval(conf, "forceRange", max_coupling_range, max_coupling_range)) { //set to default - for(i = 0; i < colvars.size(); i++) { - if(cvm::temperature() > 0) + for (i = 0; i < colvars.size(); i++) { + if (cvm::temperature() > 0) max_coupling_range[i] = 3 * cvm::temperature() * cvm::boltzmann(); else max_coupling_range[i] = 3 * cvm::boltzmann(); } } - if(!get_keyval (conf, "rateMax", max_coupling_rate, max_coupling_rate)) { + if (!get_keyval(conf, "rateMax", max_coupling_rate, max_coupling_rate)) { //set to default - for(i = 0; i < colvars.size(); i++) { + for (i = 0; i < colvars.size(); i++) { max_coupling_rate[i] = max_coupling_range[i] / (10 * update_freq); } } if (cvm::debug()) - cvm::log (" bias.\n"); + cvm::log(" bias.\n"); } colvarbias_alb::~colvarbias_alb() { if (cvm::n_rest_biases > 0) cvm::n_rest_biases -= 1; } cvm::real colvarbias_alb::update() { bias_energy = 0.0; update_calls++; if (cvm::debug()) - cvm::log ("Updating the adaptive linear bias \""+this->name+"\".\n"); + cvm::log("Updating the adaptive linear bias \""+this->name+"\".\n"); //log the moments of the CVs // Force and energy calculation bool finished_equil_flag = 1; cvm::real delta; for (size_t i = 0; i < colvars.size(); i++) { colvar_forces[i] = -1.0 * restraint_force(restraint_convert_k(current_coupling[i], colvars[i]->width), colvars[i], colvar_centers[i]); bias_energy += restraint_potential(restraint_convert_k(current_coupling[i], colvars[i]->width), colvars[i], colvar_centers[i]); - if(!b_equilibration) { + if (!b_equilibration) { //Welford, West, and Hanso online variance method delta = static_cast(colvars[i]->value()) - means[i]; means[i] += delta / update_calls; ssd[i] += delta * (static_cast(colvars[i]->value()) - means[i]); } else { //check if we've reached the setpoint - if(coupling_rate[i] == 0 || pow(current_coupling[i] - set_coupling[i],2) < pow(coupling_rate[i],2)) { + if (coupling_rate[i] == 0 || pow(current_coupling[i] - set_coupling[i],2) < pow(coupling_rate[i],2)) { finished_equil_flag &= 1; //we continue equilibrating as long as we haven't reached all the set points } else { current_coupling[i] += coupling_rate[i]; finished_equil_flag = 0; } //update max_coupling_range - if(!b_hard_coupling_range && fabs(current_coupling[i]) > max_coupling_range[i]) { + if (!b_hard_coupling_range && fabs(current_coupling[i]) > max_coupling_range[i]) { std::ostringstream logStream; logStream << "Coupling constant for " << colvars[i]->name << " has exceeded coupling range of " << max_coupling_range[i] << ".\n"; max_coupling_range[i] *= 1.25; logStream << "Expanding coupling range to " << max_coupling_range[i] << ".\n"; cvm::log(logStream.str()); } } } - if(b_equilibration && finished_equil_flag) { + if (b_equilibration && finished_equil_flag) { b_equilibration = false; update_calls = 0; } //now we update coupling constant, if necessary - if(!b_equilibration && update_calls == update_freq) { + if (!b_equilibration && update_calls == update_freq) { //use estimated variance to take a step cvm::real step_size = 0; cvm::real temp; //reset means and sum of squares of differences - for(size_t i = 0; i < colvars.size(); i++) { + for (size_t i = 0; i < colvars.size(); i++) { temp = 2. * (means[i] / (static_cast (colvar_centers[i])) - 1) * ssd[i] / (update_calls - 1); - if(cvm::temperature() > 0) + if (cvm::temperature() > 0) step_size = temp / (cvm::temperature() * cvm::boltzmann()); else step_size = temp / cvm::boltzmann(); means[i] = 0; ssd[i] = 0; //stochastic if we do that update or not - if(colvars.size() == 1 || rand() < RAND_MAX / ((int) colvars.size())) { + if (colvars.size() == 1 || rand() < RAND_MAX / ((int) colvars.size())) { coupling_accum[i] += step_size * step_size; current_coupling[i] = set_coupling[i]; set_coupling[i] += max_coupling_range[i] / sqrt(coupling_accum[i]) * step_size; coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq; //set to the minimum rate and then put the sign back on it coupling_rate[i] = copysign(fmin(fabs(coupling_rate[i]), max_coupling_rate[i]), coupling_rate[i]); } else { coupling_rate[i] = 0; } } update_calls = 0; b_equilibration = true; } return bias_energy; } -std::istream & colvarbias_alb::read_restart (std::istream &is) +std::istream & colvarbias_alb::read_restart(std::istream &is) { size_t const start_pos = is.tellg(); - cvm::log ("Restarting adaptive linear bias \""+ + cvm::log("Restarting adaptive linear bias \""+ this->name+"\".\n"); std::string key, brace, conf; if ( !(is >> key) || !(key == "ALB") || !(is >> brace) || !(brace == "{") || - !(is >> colvarparse::read_block ("configuration", conf)) ) { + !(is >> colvarparse::read_block("configuration", conf)) ) { - cvm::log ("Error: in reading restart configuration for restraint bias \""+ + cvm::log("Error: in reading restart configuration for restraint bias \""+ this->name+"\" at position "+ - cvm::to_str (is.tellg())+" in stream.\n"); + cvm::to_str(is.tellg())+" in stream.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } std::string name = ""; - if ( (colvarparse::get_keyval (conf, "name", name, std::string (""), colvarparse::parse_silent)) && + if ( (colvarparse::get_keyval(conf, "name", name, std::string(""), colvarparse::parse_silent)) && (name != this->name) ) - cvm::fatal_error ("Error: in the restart file, the " + cvm::fatal_error("Error: in the restart file, the " "\"ALB\" block has a wrong name\n"); if (name.size() == 0) { - cvm::fatal_error ("Error: \"ALB\" block in the restart file " + cvm::fatal_error("Error: \"ALB\" block in the restart file " "has no identifiers.\n"); } - if (!get_keyval (conf, "setCoupling", set_coupling)) - cvm::fatal_error ("Error: current setCoupling is missing from the restart.\n"); + if (!get_keyval(conf, "setCoupling", set_coupling)) + cvm::fatal_error("Error: current setCoupling is missing from the restart.\n"); - if (!get_keyval (conf, "currentCoupling", current_coupling)) - cvm::fatal_error ("Error: current setCoupling is missing from the restart.\n"); + if (!get_keyval(conf, "currentCoupling", current_coupling)) + cvm::fatal_error("Error: current setCoupling is missing from the restart.\n"); - if (!get_keyval (conf, "maxCouplingRange", max_coupling_range)) - cvm::fatal_error ("Error: maxCouplingRange is missing from the restart.\n"); + if (!get_keyval(conf, "maxCouplingRange", max_coupling_range)) + cvm::fatal_error("Error: maxCouplingRange is missing from the restart.\n"); - if (!get_keyval (conf, "couplingRate", coupling_rate)) - cvm::fatal_error ("Error: current setCoupling is missing from the restart.\n"); + if (!get_keyval(conf, "couplingRate", coupling_rate)) + cvm::fatal_error("Error: current setCoupling is missing from the restart.\n"); - if (!get_keyval (conf, "couplingAccum", coupling_accum)) - cvm::fatal_error ("Error: couplingAccum is missing from the restart.\n"); + if (!get_keyval(conf, "couplingAccum", coupling_accum)) + cvm::fatal_error("Error: couplingAccum is missing from the restart.\n"); - if (!get_keyval (conf, "mean", means)) - cvm::fatal_error ("Error: current mean is missing from the restart.\n"); + if (!get_keyval(conf, "mean", means)) + cvm::fatal_error("Error: current mean is missing from the restart.\n"); - if (!get_keyval (conf, "ssd", ssd)) - cvm::fatal_error ("Error: current ssd is missing from the restart.\n"); + if (!get_keyval(conf, "ssd", ssd)) + cvm::fatal_error("Error: current ssd is missing from the restart.\n"); - if (!get_keyval (conf, "updateCalls", update_calls)) - cvm::fatal_error ("Error: current updateCalls is missing from the restart.\n"); + if (!get_keyval(conf, "updateCalls", update_calls)) + cvm::fatal_error("Error: current updateCalls is missing from the restart.\n"); - if (!get_keyval (conf, "b_equilibration", b_equilibration)) - cvm::fatal_error ("Error: current updateCalls is missing from the restart.\n"); + if (!get_keyval(conf, "b_equilibration", b_equilibration)) + cvm::fatal_error("Error: current updateCalls is missing from the restart.\n"); is >> brace; if (brace != "}") { - cvm::fatal_error ("Error: corrupt restart information for adaptive linear bias \""+ + cvm::fatal_error("Error: corrupt restart information for adaptive linear bias \""+ this->name+"\": no matching brace at position "+ - cvm::to_str (is.tellg())+" in the restart file.\n"); - is.setstate (std::ios::failbit); + cvm::to_str(is.tellg())+" in the restart file.\n"); + is.setstate(std::ios::failbit); } return is; } -std::ostream & colvarbias_alb::write_restart (std::ostream &os) +std::ostream & colvarbias_alb::write_restart(std::ostream &os) { os << "ALB {\n" << " configuration {\n" << " name " << this->name << "\n"; os << " setCoupling "; size_t i; - for(i = 0; i < colvars.size(); i++) { - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << set_coupling[i] << "\n"; + for (i = 0; i < colvars.size(); i++) { + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << set_coupling[i] << "\n"; } os << " currentCoupling "; - for(i = 0; i < colvars.size(); i++) { - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << current_coupling[i] << "\n"; + for (i = 0; i < colvars.size(); i++) { + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << current_coupling[i] << "\n"; } os << " maxCouplingRange "; - for(i = 0; i < colvars.size(); i++) { - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << max_coupling_range[i] << "\n"; + for (i = 0; i < colvars.size(); i++) { + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << max_coupling_range[i] << "\n"; } os << " couplingRate "; - for(i = 0; i < colvars.size(); i++) { - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << coupling_rate[i] << "\n"; + for (i = 0; i < colvars.size(); i++) { + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << coupling_rate[i] << "\n"; } os << " couplingAccum "; - for(i = 0; i < colvars.size(); i++) { - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << coupling_accum[i] << "\n"; + for (i = 0; i < colvars.size(); i++) { + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << coupling_accum[i] << "\n"; } os << " mean "; - for(i = 0; i < colvars.size(); i++) { - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << means[i] << "\n"; + for (i = 0; i < colvars.size(); i++) { + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << means[i] << "\n"; } os << " ssd "; - for(i = 0; i < colvars.size(); i++) { - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << ssd[i] << "\n"; + for (i = 0; i < colvars.size(); i++) { + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << ssd[i] << "\n"; } os << " updateCalls " << update_calls << "\n"; - if(b_equilibration) + if (b_equilibration) os << " b_equilibration yes\n"; else os << " b_equilibration no\n"; os << " }\n" << "}\n\n"; return os; } -std::ostream & colvarbias_alb::write_traj_label (std::ostream &os) +std::ostream & colvarbias_alb::write_traj_label(std::ostream &os) { os << " "; if (b_output_energy) os << " E_" - << cvm::wrap_string (this->name, cvm::en_width-2); + << cvm::wrap_string(this->name, cvm::en_width-2); if (b_output_coupling) - for(size_t i = 0; i < current_coupling.size(); i++) { + for (size_t i = 0; i < current_coupling.size(); i++) { os << " ForceConst_" << i <name, cvm::cv_width - 4); } if (b_output_centers) for (size_t i = 0; i < colvars.size(); i++) { - size_t const this_cv_width = (colvars[i]->value()).output_width (cvm::cv_width); + size_t const this_cv_width = (colvars[i]->value()).output_width(cvm::cv_width); os << " x0_" - << cvm::wrap_string (colvars[i]->name, this_cv_width-3); + << cvm::wrap_string(colvars[i]->name, this_cv_width-3); } return os; } -std::ostream & colvarbias_alb::write_traj (std::ostream &os) +std::ostream & colvarbias_alb::write_traj(std::ostream &os) { os << " "; if (b_output_energy) os << " " - << std::setprecision (cvm::en_prec) << std::setw (cvm::en_width) + << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width) << bias_energy; - if(b_output_coupling) - for(size_t i = 0; i < current_coupling.size(); i++) { + if (b_output_coupling) + for (size_t i = 0; i < current_coupling.size(); i++) { os << " " - << std::setprecision (cvm::en_prec) << std::setw (cvm::en_width) + << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width) << current_coupling[i]; } if (b_output_centers) for (size_t i = 0; i < colvars.size(); i++) { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << colvar_centers[i]; } - if(b_output_grad) - for(size_t i = 0; i < means.size(); i++) { + if (b_output_grad) + for (size_t i = 0; i < means.size(); i++) { os << " " << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << -2. * (means[i] / (static_cast (colvar_centers[i])) - 1) * ssd[i] / (fmax(update_calls,2) - 1); } return os; } cvm::real colvarbias_alb::restraint_potential(cvm::real k, const colvar* x, const colvarvalue &xcenter) const { return k * (x->value() - xcenter); } colvarvalue colvarbias_alb::restraint_force(cvm::real k, const colvar* x, const colvarvalue &xcenter) const { return k; } cvm::real colvarbias_alb::restraint_convert_k(cvm::real k, cvm::real dist_measure) const { return k / dist_measure; } diff --git a/lib/colvars/colvarbias_alb.h b/lib/colvars/colvarbias_alb.h index a79a9861e..d8c46b499 100644 --- a/lib/colvars/colvarbias_alb.h +++ b/lib/colvars/colvarbias_alb.h @@ -1,85 +1,87 @@ +// -*- c++ -*- + #ifndef COLVARBIAS_ALB_H #define COLVARBIAS_ALB_H #include "colvar.h" #include "colvarbias_restraint.h" class colvarbias_alb : public colvarbias { public: colvarbias_alb(std::string const &conf, char const *key); virtual ~colvarbias_alb(); virtual cvm::real update(); /// Read the bias configuration from a restart file - virtual std::istream & read_restart (std::istream &is); + virtual std::istream & read_restart(std::istream &is); /// Write the bias configuration to a restart file - virtual std::ostream & write_restart (std::ostream &os); + virtual std::ostream & write_restart(std::ostream &os); /// Write a label to the trajectory file (comment line) - virtual std::ostream & write_traj_label (std::ostream &os); + virtual std::ostream & write_traj_label(std::ostream &os); /// Output quantities such as the bias energy to the trajectory file - virtual std::ostream & write_traj (std::ostream &os); + virtual std::ostream & write_traj(std::ostream &os); protected: /// \brief Restraint centers std::vector colvar_centers; /// \brief colvar parameters, used for calculating the gradient/variance std::vector means; std::vector ssd; // SSD = sum of squares of differences from mean int update_calls; ///\brief how often to update coupling constant int update_freq; ///\brief Estimated range of coupling constant values in kT std::vector max_coupling_range; //\brief Estimated max for how quickly the rate can change in kT / time std::vector max_coupling_rate; /// \brief accumated couping force; used in stochastic online gradient descent algorithm std::vector coupling_accum; /// \brief coupling constant std::vector set_coupling; /// \brief current coupling constant, which is ramped up during equilibration to coupling std::vector current_coupling; /// \brief how quickly to change the coupling constant std::vector coupling_rate; // \brief if we're equilibrating our estimates or collecting data bool b_equilibration; // \brief If the coupling range should be increased bool b_hard_coupling_range; /// \brief flag for outputting colvar centers bool b_output_centers; /// \brief flag for outputting current gradient bool b_output_grad; /// \brief flag for outputting coupling constant bool b_output_coupling; cvm::real restraint_potential(cvm::real k, const colvar* x, const colvarvalue& xcenter) const; /// \brief Force function colvarvalue restraint_force(cvm::real k, const colvar* x, const colvarvalue& xcenter) const; ///\brief Unit scaling cvm::real restraint_convert_k(cvm::real k, cvm::real dist_measure) const; }; #endif diff --git a/lib/colvars/colvarbias_meta.cpp b/lib/colvars/colvarbias_meta.cpp index 5e4e002de..e8e104366 100644 --- a/lib/colvars/colvarbias_meta.cpp +++ b/lib/colvars/colvarbias_meta.cpp @@ -1,1734 +1,1745 @@ /// -*- c++ -*- #include #include #include #include #include #include // used to set the absolute path of a replica file -#if defined (WIN32) && !defined(__CYGWIN__) +#if defined(WIN32) && !defined(__CYGWIN__) #include #define CHDIR ::_chdir #define GETCWD ::_getcwd #define PATHSEP "\\" #else #include #define CHDIR ::chdir #define GETCWD ::getcwd #define PATHSEP "/" #endif #include "colvar.h" #include "colvarbias_meta.h" colvarbias_meta::colvarbias_meta() : colvarbias(), - new_hills_begin (hills.end()), - state_file_step (0) + new_hills_begin(hills.end()), + state_file_step(0) { } -colvarbias_meta::colvarbias_meta (std::string const &conf, char const *key) - : colvarbias (conf, key), - new_hills_begin (hills.end()), - state_file_step (0) +colvarbias_meta::colvarbias_meta(std::string const &conf, char const *key) + : colvarbias(conf, key), + new_hills_begin(hills.end()), + state_file_step(0) { if (cvm::n_abf_biases > 0) - cvm::log ("Warning: running ABF and metadynamics together is not recommended unless applyBias is off for ABF.\n"); + cvm::log("Warning: running ABF and metadynamics together is not recommended unless applyBias is off for ABF.\n"); - get_keyval (conf, "hillWeight", hill_weight, 0.01); + get_keyval(conf, "hillWeight", hill_weight, 0.01); if (hill_weight == 0.0) - cvm::log ("Warning: hillWeight has been set to zero, " + cvm::log("Warning: hillWeight has been set to zero, " "this bias will have no effect.\n"); - get_keyval (conf, "newHillFrequency", new_hill_freq, 1000); + get_keyval(conf, "newHillFrequency", new_hill_freq, 1000); - get_keyval (conf, "hillWidth", hill_width, std::sqrt (2.0 * PI) / 2.0); + get_keyval(conf, "hillWidth", hill_width, std::sqrt(2.0 * PI) / 2.0); { bool b_replicas = false; - get_keyval (conf, "multipleReplicas", b_replicas, false); + get_keyval(conf, "multipleReplicas", b_replicas, false); if (b_replicas) comm = multiple_replicas; else comm = single_replica; } - get_keyval (conf, "useGrids", use_grids, true); + get_keyval(conf, "useGrids", use_grids, true); if (use_grids) { - get_keyval (conf, "gridsUpdateFrequency", grids_freq, new_hill_freq); - get_keyval (conf, "rebinGrids", rebin_grids, false); + get_keyval(conf, "gridsUpdateFrequency", grids_freq, new_hill_freq); + get_keyval(conf, "rebinGrids", rebin_grids, false); expand_grids = false; size_t i; for (i = 0; i < colvars.size(); i++) { if (colvars[i]->expand_boundaries) { expand_grids = true; - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": Will expand grids when the colvar \""+ colvars[i]->name+"\" approaches its boundaries.\n"); } } - get_keyval (conf, "keepHills", keep_hills, false); - if (! get_keyval (conf, "writeFreeEnergyFile", dump_fes, true)) - get_keyval (conf, "dumpFreeEnergyFile", dump_fes, true, colvarparse::parse_silent); - get_keyval (conf, "saveFreeEnergyFile", dump_fes_save, false); + get_keyval(conf, "keepHills", keep_hills, false); + if (! get_keyval(conf, "writeFreeEnergyFile", dump_fes, true)) + get_keyval(conf, "dumpFreeEnergyFile", dump_fes, true, colvarparse::parse_silent); + get_keyval(conf, "saveFreeEnergyFile", dump_fes_save, false); for (i = 0; i < colvars.size(); i++) { - colvars[i]->enable (colvar::task_grid); + colvars[i]->enable(colvar::task_grid); } hills_energy = new colvar_grid_scalar (colvars); - hills_energy_gradients = new colvar_grid_gradient (colvars); + hills_energy_gradients = new colvar_grid_gradient(colvars); } else { rebin_grids = false; keep_hills = false; dump_fes = false; dump_fes_save = false; dump_replica_fes = false; hills_energy = NULL; hills_energy_gradients = NULL; } if (comm != single_replica) { if (expand_grids) - cvm::fatal_error ("Error: expandBoundaries is not supported when " + cvm::fatal_error("Error: expandBoundaries is not supported when " "using more than one replicas; please allocate " "wide enough boundaries for each colvar" "ahead of time.\n"); - if (get_keyval (conf, "dumpPartialFreeEnergyFile", dump_replica_fes, false)) { + if (get_keyval(conf, "dumpPartialFreeEnergyFile", dump_replica_fes, false)) { if (dump_replica_fes && (! dump_fes)) { - cvm::log ("Enabling \"dumpFreeEnergyFile\".\n"); + cvm::log("Enabling \"dumpFreeEnergyFile\".\n"); } } - get_keyval (conf, "replicaID", replica_id, std::string ("")); + get_keyval(conf, "replicaID", replica_id, std::string("")); if (!replica_id.size()) - cvm::fatal_error ("Error: replicaID must be defined " + cvm::fatal_error("Error: replicaID must be defined " "when using more than one replica.\n"); - get_keyval (conf, "replicasRegistry", + get_keyval(conf, "replicasRegistry", replicas_registry_file, (this->name+".replicas.registry.txt")); - get_keyval (conf, "replicaUpdateFrequency", + get_keyval(conf, "replicaUpdateFrequency", replica_update_freq, new_hill_freq); if (keep_hills) - cvm::log ("Warning: in metadynamics bias \""+this->name+"\""+ + cvm::log("Warning: in metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": keepHills with more than one replica can lead to a very " "large amount input/output and slow down your calculations. " "Please consider disabling it.\n"); { // TODO: one may want to specify the path manually for intricated filesystems? char *pwd = new char[3001]; - if (GETCWD (pwd, 3000) == NULL) - cvm::fatal_error ("Error: cannot get the path of the current working directory.\n"); + if (GETCWD(pwd, 3000) == NULL) + cvm::fatal_error("Error: cannot get the path of the current working directory.\n"); replica_list_file = - (std::string (pwd)+std::string (PATHSEP)+ + (std::string(pwd)+std::string(PATHSEP)+ this->name+"."+replica_id+".files.txt"); // replica_hills_file and replica_state_file are those written // by the current replica; within the mirror biases, they are // those by another replica replica_hills_file = - (std::string (pwd)+std::string (PATHSEP)+ + (std::string(pwd)+std::string(PATHSEP)+ cvm::output_prefix+".colvars."+this->name+"."+replica_id+".hills"); replica_state_file = - (std::string (pwd)+std::string (PATHSEP)+ + (std::string(pwd)+std::string(PATHSEP)+ cvm::output_prefix+".colvars."+this->name+"."+replica_id+".state"); delete[] pwd; } // now register this replica // first check that it isn't already there bool registered_replica = false; - std::ifstream reg_is (replicas_registry_file.c_str()); + std::ifstream reg_is(replicas_registry_file.c_str()); if (reg_is.good()) { // the file may not be there yet - std::string existing_replica (""); - std::string existing_replica_file (""); + std::string existing_replica(""); + std::string existing_replica_file(""); while ((reg_is >> existing_replica) && existing_replica.size() && (reg_is >> existing_replica_file) && existing_replica_file.size()) { if (existing_replica == replica_id) { // this replica was already registered replica_list_file = existing_replica_file; reg_is.close(); registered_replica = true; break; } } reg_is.close(); } // if this replica was not included yet, we should generate a // new record for it: but first, we write this replica's files, // for the others to read // open the "hills" buffer file - replica_hills_os.open (replica_hills_file.c_str()); + replica_hills_os.open(replica_hills_file.c_str()); if (!replica_hills_os.good()) - cvm::fatal_error ("Error: in opening file \""+ + cvm::fatal_error("Error: in opening file \""+ replica_hills_file+"\" for writing.\n"); - replica_hills_os.setf (std::ios::scientific, std::ios::floatfield); + replica_hills_os.setf(std::ios::scientific, std::ios::floatfield); // write the state file (so that there is always one available) write_replica_state_file(); // schedule to read the state files of the other replicas for (size_t ir = 0; ir < replicas.size(); ir++) { (replicas[ir])->replica_state_file_in_sync = false; } // if we're running without grids, use a growing list of "hills" files // otherwise, just one state file and one "hills" file as buffer - std::ofstream list_os (replica_list_file.c_str(), + std::ofstream list_os(replica_list_file.c_str(), (use_grids ? std::ios::trunc : std::ios::app)); if (! list_os.good()) - cvm::fatal_error ("Error: in opening file \""+ + cvm::fatal_error("Error: in opening file \""+ replica_list_file+"\" for writing.\n"); list_os << "stateFile " << replica_state_file << "\n"; list_os << "hillsFile " << replica_hills_file << "\n"; list_os.close(); // finally, if add a new record for this replica to the registry if (! registered_replica) { - std::ofstream reg_os (replicas_registry_file.c_str(), std::ios::app); + std::ofstream reg_os(replicas_registry_file.c_str(), std::ios::app); if (! reg_os.good()) - cvm::fatal_error ("Error: in opening file \""+ + cvm::fatal_error("Error: in opening file \""+ replicas_registry_file+"\" for writing.\n"); reg_os << replica_id << " " << replica_list_file << "\n"; reg_os.close(); } } - get_keyval (conf, "writeHillsTrajectory", b_hills_traj, false); + get_keyval(conf, "writeHillsTrajectory", b_hills_traj, false); if (b_hills_traj) { - std::string const traj_file_name (cvm::output_prefix+ + std::string const traj_file_name(cvm::output_prefix+ ".colvars."+this->name+ ( (comm != single_replica) ? ("."+replica_id) : ("") )+ ".hills.traj"); - hills_traj_os.open (traj_file_name.c_str()); + hills_traj_os.open(traj_file_name.c_str()); if (!hills_traj_os.good()) - cvm::fatal_error ("Error: in opening hills output file \"" + + cvm::fatal_error("Error: in opening hills output file \"" + traj_file_name + "\".\n"); } // for well-tempered metadynamics - get_keyval (conf, "wellTempered", well_tempered, false); - get_keyval (conf, "biasTemperature", bias_temperature, -1.0); + get_keyval(conf, "wellTempered", well_tempered, false); + get_keyval(conf, "biasTemperature", bias_temperature, -1.0); if ((bias_temperature == -1.0) && well_tempered) { - cvm::fatal_error ("Error: biasTemperature is not set.\n"); + cvm::fatal_error("Error: biasTemperature is not set.\n"); } if (well_tempered) { cvm::log("Well-tempered metadynamics is used.\n"); cvm::log("The bias temperature is "+cvm::to_str(bias_temperature)+".\n"); } if (cvm::debug()) - cvm::log ("Done initializing the metadynamics bias \""+this->name+"\""+ + cvm::log("Done initializing the metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n"); save_delimiters = false; } colvarbias_meta::~colvarbias_meta() { if (hills_energy) { delete hills_energy; hills_energy = NULL; } if (hills_energy_gradients) { delete hills_energy_gradients; hills_energy_gradients = NULL; } if (replica_hills_os.good()) replica_hills_os.close(); if (hills_traj_os.good()) hills_traj_os.close(); if (cvm::n_meta_biases > 0) cvm::n_meta_biases -= 1; } // ********************************************************************** // Hill management member functions // ********************************************************************** std::list::const_iterator -colvarbias_meta::create_hill (colvarbias_meta::hill const &h) +colvarbias_meta::create_hill(colvarbias_meta::hill const &h) { hill_iter const hills_end = hills.end(); - hills.push_back (h); + hills.push_back(h); if (new_hills_begin == hills_end) { // if new_hills_begin is unset, set it for the first time new_hills_begin = hills.end(); new_hills_begin--; } if (use_grids) { // also add it to the list of hills that are off-grid, which may // need to be computed analytically when the colvar returns // off-grid - cvm::real const min_dist = hills_energy->bin_distance_from_boundaries (h.centers, true); - if (min_dist < (3.0 * std::floor (hill_width)) + 1.0) { - hills_off_grid.push_back (h); + cvm::real const min_dist = hills_energy->bin_distance_from_boundaries(h.centers, true); + if (min_dist < (3.0 * std::floor(hill_width)) + 1.0) { + hills_off_grid.push_back(h); } } // output to trajectory (if specified) if (hills_traj_os.good()) { hills_traj_os << (hills.back()).output_traj(); if (cvm::debug()) { hills_traj_os.flush(); } } has_data = true; return hills.end(); } std::list::const_iterator -colvarbias_meta::delete_hill (hill_iter &h) +colvarbias_meta::delete_hill(hill_iter &h) { if (cvm::debug()) { - cvm::log ("Deleting hill from the metadynamics bias \""+this->name+"\""+ + cvm::log("Deleting hill from the metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ", with step number "+ - cvm::to_str (h->it)+(h->replica.size() ? + cvm::to_str(h->it)+(h->replica.size() ? ", replica id \""+h->replica : "")+".\n"); } if (use_grids && !hills_off_grid.empty()) { for (hill_iter hoff = hills_off_grid.begin(); hoff != hills_off_grid.end(); hoff++) { if (*h == *hoff) { - hills_off_grid.erase (hoff); + hills_off_grid.erase(hoff); break; } } } if (hills_traj_os.good()) { // output to the trajectory hills_traj_os << "# DELETED this hill: " << (hills.back()).output_traj() << "\n"; if (cvm::debug()) hills_traj_os.flush(); } - return hills.erase (h); + return hills.erase(h); } cvm::real colvarbias_meta::update() { if (cvm::debug()) - cvm::log ("Updating the metadynamics bias \""+this->name+"\""+ + cvm::log("Updating the metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n"); if (use_grids) { std::vector curr_bin = hills_energy->get_colvars_index(); if (expand_grids) { // first of all, expand the grids, if specified if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": current coordinates on the grid: "+ - cvm::to_str (curr_bin)+".\n"); + cvm::to_str(curr_bin)+".\n"); bool changed_grids = false; int const min_buffer = - (3 * (size_t) std::floor (hill_width)) + 1; + (3 * (size_t) std::floor(hill_width)) + 1; - std::vector new_sizes (hills_energy->sizes()); - std::vector new_lower_boundaries (hills_energy->lower_boundaries); - std::vector new_upper_boundaries (hills_energy->upper_boundaries); + std::vector new_sizes(hills_energy->sizes()); + std::vector new_lower_boundaries(hills_energy->lower_boundaries); + std::vector new_upper_boundaries(hills_energy->upper_boundaries); for (size_t i = 0; i < colvars.size(); i++) { if (! colvars[i]->expand_boundaries) continue; cvm::real &new_lb = new_lower_boundaries[i].real_value; cvm::real &new_ub = new_upper_boundaries[i].real_value; int &new_size = new_sizes[i]; bool changed_lb = false, changed_ub = false; if (!colvars[i]->hard_lower_boundary) if (curr_bin[i] < min_buffer) { int const extra_points = (min_buffer - curr_bin[i]); new_lb -= extra_points * colvars[i]->width; new_size += extra_points; // changed offset in this direction => the pointer needs to // be changed, too curr_bin[i] += extra_points; changed_lb = true; - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": new lower boundary for colvar \""+ colvars[i]->name+"\", at "+ - cvm::to_str (new_lower_boundaries[i])+".\n"); + cvm::to_str(new_lower_boundaries[i])+".\n"); } if (!colvars[i]->hard_upper_boundary) if (curr_bin[i] > new_size - min_buffer - 1) { int const extra_points = (curr_bin[i] - (new_size - 1) + min_buffer); new_ub += extra_points * colvars[i]->width; new_size += extra_points; changed_ub = true; - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": new upper boundary for colvar \""+ colvars[i]->name+"\", at "+ - cvm::to_str (new_upper_boundaries[i])+".\n"); + cvm::to_str(new_upper_boundaries[i])+".\n"); } if (changed_lb || changed_ub) changed_grids = true; } if (changed_grids) { // map everything into new grids colvar_grid_scalar *new_hills_energy = - new colvar_grid_scalar (*hills_energy); + new colvar_grid_scalar(*hills_energy); colvar_grid_gradient *new_hills_energy_gradients = - new colvar_grid_gradient (*hills_energy_gradients); + new colvar_grid_gradient(*hills_energy_gradients); // supply new boundaries to the new grids new_hills_energy->lower_boundaries = new_lower_boundaries; new_hills_energy->upper_boundaries = new_upper_boundaries; - new_hills_energy->create (new_sizes, 0.0, 1); + new_hills_energy->create(new_sizes, 0.0, 1); new_hills_energy_gradients->lower_boundaries = new_lower_boundaries; new_hills_energy_gradients->upper_boundaries = new_upper_boundaries; - new_hills_energy_gradients->create (new_sizes, 0.0, colvars.size()); + new_hills_energy_gradients->create(new_sizes, 0.0, colvars.size()); - new_hills_energy->map_grid (*hills_energy); - new_hills_energy_gradients->map_grid (*hills_energy_gradients); + new_hills_energy->map_grid(*hills_energy); + new_hills_energy_gradients->map_grid(*hills_energy_gradients); delete hills_energy; delete hills_energy_gradients; hills_energy = new_hills_energy; hills_energy_gradients = new_hills_energy_gradients; curr_bin = hills_energy->get_colvars_index(); if (cvm::debug()) - cvm::log ("Coordinates on the new grid: "+ - cvm::to_str (curr_bin)+".\n"); + cvm::log("Coordinates on the new grid: "+ + cvm::to_str(curr_bin)+".\n"); } } } // add a new hill if the required time interval has passed if ((cvm::step_absolute() % new_hill_freq) == 0) { if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ - ": adding a new hill at step "+cvm::to_str (cvm::step_absolute())+".\n"); + ": adding a new hill at step "+cvm::to_str(cvm::step_absolute())+".\n"); switch (comm) { case single_replica: if (well_tempered) { cvm::real hills_energy_sum_here = 0.0; if (use_grids) { std::vector curr_bin = hills_energy->get_colvars_index(); hills_energy_sum_here = hills_energy->value(curr_bin); } else { - calc_hills (new_hills_begin, hills.end(), hills_energy_sum_here); + calc_hills(new_hills_begin, hills.end(), hills_energy_sum_here); } cvm::real const exp_weight = std::exp(-1.0*hills_energy_sum_here/(bias_temperature*cvm::boltzmann())); - create_hill (hill ((hill_weight*exp_weight), colvars, hill_width)); + create_hill(hill((hill_weight*exp_weight), colvars, hill_width)); } else { - create_hill (hill (hill_weight, colvars, hill_width)); + create_hill(hill(hill_weight, colvars, hill_width)); } break; case multiple_replicas: if (well_tempered) { cvm::real hills_energy_sum_here = 0.0; if (use_grids) { std::vector curr_bin = hills_energy->get_colvars_index(); hills_energy_sum_here = hills_energy->value(curr_bin); } else { - calc_hills (new_hills_begin, hills.end(), hills_energy_sum_here); + calc_hills(new_hills_begin, hills.end(), hills_energy_sum_here); } cvm::real const exp_weight = std::exp(-1.0*hills_energy_sum_here/(bias_temperature*cvm::boltzmann())); - create_hill (hill ((hill_weight*exp_weight), colvars, hill_width, replica_id)); + create_hill(hill((hill_weight*exp_weight), colvars, hill_width, replica_id)); } else { - create_hill (hill (hill_weight, colvars, hill_width, replica_id)); + create_hill(hill(hill_weight, colvars, hill_width, replica_id)); } if (replica_hills_os.good()) { replica_hills_os << hills.back(); } else { - cvm::fatal_error ("Error: in metadynamics bias \""+this->name+"\""+ + cvm::fatal_error("Error: in metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ " while writing hills for the other replicas.\n"); } break; } } // sync with the other replicas (if needed) if (comm != single_replica) { // reread the replicas registry if ((cvm::step_absolute() % replica_update_freq) == 0) { update_replicas_registry(); // empty the output buffer replica_hills_os.flush(); read_replica_files(); } } // calculate the biasing energy and forces bias_energy = 0.0; for (size_t ir = 0; ir < colvars.size(); ir++) { colvar_forces[ir].reset(); } if (comm == multiple_replicas) for (size_t ir = 0; ir < replicas.size(); ir++) { replicas[ir]->bias_energy = 0.0; for (size_t ic = 0; ic < colvars.size(); ic++) { replicas[ir]->colvar_forces[ic].reset(); } } if (use_grids) { // get the forces from the grid if ((cvm::step_absolute() % grids_freq) == 0) { // map the most recent gaussians to the grids - project_hills (new_hills_begin, hills.end(), + project_hills(new_hills_begin, hills.end(), hills_energy, hills_energy_gradients); new_hills_begin = hills.end(); // TODO: we may want to condense all into one replicas array, // including "this" as the first element if (comm == multiple_replicas) { for (size_t ir = 0; ir < replicas.size(); ir++) { - replicas[ir]->project_hills (replicas[ir]->new_hills_begin, + replicas[ir]->project_hills(replicas[ir]->new_hills_begin, replicas[ir]->hills.end(), replicas[ir]->hills_energy, replicas[ir]->hills_energy_gradients); replicas[ir]->new_hills_begin = replicas[ir]->hills.end(); } } } std::vector curr_bin = hills_energy->get_colvars_index(); if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": current coordinates on the grid: "+ - cvm::to_str (curr_bin)+".\n"); + cvm::to_str(curr_bin)+".\n"); - if (hills_energy->index_ok (curr_bin)) { + if (hills_energy->index_ok(curr_bin)) { // within the grid: add the energy and the forces from there - bias_energy += hills_energy->value (curr_bin); + bias_energy += hills_energy->value(curr_bin); for (size_t ic = 0; ic < colvars.size(); ic++) { - cvm::real const *f = &(hills_energy_gradients->value (curr_bin)); + cvm::real const *f = &(hills_energy_gradients->value(curr_bin)); colvar_forces[ic].real_value += -1.0 * f[ic]; // the gradients are stored, not the forces } if (comm == multiple_replicas) for (size_t ir = 0; ir < replicas.size(); ir++) { - bias_energy += replicas[ir]->hills_energy->value (curr_bin); - cvm::real const *f = &(replicas[ir]->hills_energy_gradients->value (curr_bin)); + bias_energy += replicas[ir]->hills_energy->value(curr_bin); + cvm::real const *f = &(replicas[ir]->hills_energy_gradients->value(curr_bin)); for (size_t ic = 0; ic < colvars.size(); ic++) { colvar_forces[ic].real_value += -1.0 * f[ic]; } } } else { // off the grid: compute analytically only the hills at the grid's edges - calc_hills (hills_off_grid.begin(), hills_off_grid.end(), bias_energy); + calc_hills(hills_off_grid.begin(), hills_off_grid.end(), bias_energy); for (size_t ic = 0; ic < colvars.size(); ic++) { - calc_hills_force (ic, hills_off_grid.begin(), hills_off_grid.end(), colvar_forces); + calc_hills_force(ic, hills_off_grid.begin(), hills_off_grid.end(), colvar_forces); } if (comm == multiple_replicas) for (size_t ir = 0; ir < replicas.size(); ir++) { - calc_hills (replicas[ir]->hills_off_grid.begin(), + calc_hills(replicas[ir]->hills_off_grid.begin(), replicas[ir]->hills_off_grid.end(), bias_energy); for (size_t ic = 0; ic < colvars.size(); ic++) { - calc_hills_force (ic, + calc_hills_force(ic, replicas[ir]->hills_off_grid.begin(), replicas[ir]->hills_off_grid.end(), colvar_forces); } } } } // now include the hills that have not been binned yet (starting // from new_hills_begin) - calc_hills (new_hills_begin, hills.end(), bias_energy); + calc_hills(new_hills_begin, hills.end(), bias_energy); for (size_t ic = 0; ic < colvars.size(); ic++) { - calc_hills_force (ic, new_hills_begin, hills.end(), colvar_forces); + calc_hills_force(ic, new_hills_begin, hills.end(), colvar_forces); } if (cvm::debug()) - cvm::log ("Hills energy = "+cvm::to_str (bias_energy)+ - ", hills forces = "+cvm::to_str (colvar_forces)+".\n"); + cvm::log("Hills energy = "+cvm::to_str(bias_energy)+ + ", hills forces = "+cvm::to_str(colvar_forces)+".\n"); if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": adding the forces from the other replicas.\n"); if (comm == multiple_replicas) for (size_t ir = 0; ir < replicas.size(); ir++) { - calc_hills (replicas[ir]->new_hills_begin, + calc_hills(replicas[ir]->new_hills_begin, replicas[ir]->hills.end(), bias_energy); for (size_t ic = 0; ic < colvars.size(); ic++) { - calc_hills_force (ic, + calc_hills_force(ic, replicas[ir]->new_hills_begin, replicas[ir]->hills.end(), colvar_forces); } if (cvm::debug()) - cvm::log ("Hills energy = "+cvm::to_str (bias_energy)+ - ", hills forces = "+cvm::to_str (colvar_forces)+".\n"); + cvm::log("Hills energy = "+cvm::to_str(bias_energy)+ + ", hills forces = "+cvm::to_str(colvar_forces)+".\n"); } return bias_energy; } -void colvarbias_meta::calc_hills (colvarbias_meta::hill_iter h_first, +void colvarbias_meta::calc_hills(colvarbias_meta::hill_iter h_first, colvarbias_meta::hill_iter h_last, cvm::real &energy, std::vector const &colvar_values) { - std::vector curr_values (colvars.size()); + std::vector curr_values(colvars.size()); for (size_t i = 0; i < colvars.size(); i++) { - curr_values[i].type (colvars[i]->type()); + curr_values[i].type(colvars[i]->value()); } if (colvar_values.size()) { for (size_t i = 0; i < colvars.size(); i++) { curr_values[i] = colvar_values[i]; } } else { for (size_t i = 0; i < colvars.size(); i++) { curr_values[i] = colvars[i]->value(); } } for (hill_iter h = h_first; h != h_last; h++) { // compute the gaussian exponent cvm::real cv_sqdev = 0.0; for (size_t i = 0; i < colvars.size(); i++) { colvarvalue const &x = curr_values[i]; colvarvalue const ¢er = h->centers[i]; cvm::real const half_width = 0.5 * h->widths[i]; - cv_sqdev += (colvars[i]->dist2 (x, center)) / (half_width*half_width); + cv_sqdev += (colvars[i]->dist2(x, center)) / (half_width*half_width); } // compute the gaussian if (cv_sqdev > 23.0) { // set it to zero if the exponent is more negative than log(1.0E-05) - h->value (0.0); + h->value(0.0); } else { - h->value (std::exp (-0.5*cv_sqdev)); + h->value(std::exp(-0.5*cv_sqdev)); } energy += h->energy(); } } -void colvarbias_meta::calc_hills_force (size_t const &i, +void colvarbias_meta::calc_hills_force(size_t const &i, colvarbias_meta::hill_iter h_first, colvarbias_meta::hill_iter h_last, std::vector &forces, std::vector const &values) { // Retrieve the value of the colvar - colvarvalue x (values.size() ? values[i].type() : colvars[i]->type()); - x = (values.size() ? values[i] : colvars[i]->value()); + colvarvalue const x(values.size() ? values[i] : colvars[i]->value()); // do the type check only once (all colvarvalues in the hills series // were already saved with their types matching those in the // colvars) hill_iter h; - switch (colvars[i]->type()) { + switch (colvars[i]->value().type()) { case colvarvalue::type_scalar: for (h = h_first; h != h_last; h++) { if (h->value() == 0.0) continue; colvarvalue const ¢er = h->centers[i]; cvm::real const half_width = 0.5 * h->widths[i]; forces[i].real_value += ( h->weight() * h->value() * (0.5 / (half_width*half_width)) * - (colvars[i]->dist2_lgrad (x, center)).real_value ); + (colvars[i]->dist2_lgrad(x, center)).real_value ); } break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: for (h = h_first; h != h_last; h++) { if (h->value() == 0.0) continue; colvarvalue const ¢er = h->centers[i]; cvm::real const half_width = 0.5 * h->widths[i]; forces[i].rvector_value += ( h->weight() * h->value() * (0.5 / (half_width*half_width)) * - (colvars[i]->dist2_lgrad (x, center)).rvector_value ); + (colvars[i]->dist2_lgrad(x, center)).rvector_value ); } break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: for (h = h_first; h != h_last; h++) { if (h->value() == 0.0) continue; colvarvalue const ¢er = h->centers[i]; cvm::real const half_width = 0.5 * h->widths[i]; forces[i].quaternion_value += ( h->weight() * h->value() * (0.5 / (half_width*half_width)) * - (colvars[i]->dist2_lgrad (x, center)).quaternion_value ); + (colvars[i]->dist2_lgrad(x, center)).quaternion_value ); + } + break; + + case colvarvalue::type_vector: + for (h = h_first; h != h_last; h++) { + if (h->value() == 0.0) continue; + colvarvalue const ¢er = h->centers[i]; + cvm::real const half_width = 0.5 * h->widths[i]; + forces[i].vector1d_value += + ( h->weight() * h->value() * (0.5 / (half_width*half_width)) * + (colvars[i]->dist2_lgrad(x, center)).vector1d_value ); } break; case colvarvalue::type_notset: - case colvarvalue::type_all: break; } } // ********************************************************************** // grid management functions // ********************************************************************** -void colvarbias_meta::project_hills (colvarbias_meta::hill_iter h_first, +void colvarbias_meta::project_hills(colvarbias_meta::hill_iter h_first, colvarbias_meta::hill_iter h_last, colvar_grid_scalar *he, colvar_grid_gradient *hg, bool print_progress) { if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": projecting hills.\n"); // TODO: improve it by looping over a small subgrid instead of the whole grid - std::vector colvar_values (colvars.size()); - std::vector colvar_forces_scalar (colvars.size()); + std::vector colvar_values(colvars.size()); + std::vector colvar_forces_scalar(colvars.size()); std::vector he_ix = he->new_index(); std::vector hg_ix = (hg != NULL) ? hg->new_index() : std::vector (0); cvm::real hills_energy_here = 0.0; - std::vector hills_forces_here (colvars.size(), 0.0); + std::vector hills_forces_here(colvars.size(), 0.0); size_t count = 0; size_t const print_frequency = ((hills.size() >= 1000000) ? 1 : (1000000/(hills.size()+1))); if (hg != NULL) { // loop over the points of the grid for ( ; - (he->index_ok (he_ix)) && (hg->index_ok (hg_ix)); + (he->index_ok(he_ix)) && (hg->index_ok(hg_ix)); count++) { size_t i; for (i = 0; i < colvars.size(); i++) { - colvar_values[i] = hills_energy->bin_to_value_scalar (he_ix[i], i); + colvar_values[i] = hills_energy->bin_to_value_scalar(he_ix[i], i); } // loop over the hills and increment the energy grid locally hills_energy_here = 0.0; - calc_hills (h_first, h_last, hills_energy_here, colvar_values); - he->acc_value (he_ix, hills_energy_here); + calc_hills(h_first, h_last, hills_energy_here, colvar_values); + he->acc_value(he_ix, hills_energy_here); for (i = 0; i < colvars.size(); i++) { hills_forces_here[i].reset(); - calc_hills_force (i, h_first, h_last, hills_forces_here, colvar_values); + calc_hills_force(i, h_first, h_last, hills_forces_here, colvar_values); colvar_forces_scalar[i] = hills_forces_here[i].real_value; } - hg->acc_force (hg_ix, &(colvar_forces_scalar.front())); + hg->acc_force(hg_ix, &(colvar_forces_scalar.front())); - he->incr (he_ix); - hg->incr (hg_ix); + he->incr(he_ix); + hg->incr(hg_ix); if ((count % print_frequency) == 0) { if (print_progress) { - cvm::real const progress = cvm::real (count) / cvm::real (hg->number_of_points()); + cvm::real const progress = cvm::real(count) / cvm::real(hg->number_of_points()); std::ostringstream os; - os.setf (std::ios::fixed, std::ios::floatfield); - os << std::setw (6) << std::setprecision (2) + os.setf(std::ios::fixed, std::ios::floatfield); + os << std::setw(6) << std::setprecision(2) << 100.0 * progress << "% done."; - cvm::log (os.str()); + cvm::log(os.str()); } } } } else { // simpler version, with just the energy - for ( ; (he->index_ok (he_ix)); ) { + for ( ; (he->index_ok(he_ix)); ) { for (size_t i = 0; i < colvars.size(); i++) { - colvar_values[i] = hills_energy->bin_to_value_scalar (he_ix[i], i); + colvar_values[i] = hills_energy->bin_to_value_scalar(he_ix[i], i); } hills_energy_here = 0.0; - calc_hills (h_first, h_last, hills_energy_here, colvar_values); - he->acc_value (he_ix, hills_energy_here); + calc_hills(h_first, h_last, hills_energy_here, colvar_values); + he->acc_value(he_ix, hills_energy_here); - he->incr (he_ix); + he->incr(he_ix); count++; if ((count % print_frequency) == 0) { if (print_progress) { - cvm::real const progress = cvm::real (count) / cvm::real (he->number_of_points()); + cvm::real const progress = cvm::real(count) / cvm::real(he->number_of_points()); std::ostringstream os; - os.setf (std::ios::fixed, std::ios::floatfield); - os << std::setw (6) << std::setprecision (2) + os.setf(std::ios::fixed, std::ios::floatfield); + os << std::setw(6) << std::setprecision(2) << 100.0 * progress << "% done."; - cvm::log (os.str()); + cvm::log(os.str()); } } } } if (print_progress) { - cvm::log ("100.00% done."); + cvm::log("100.00% done."); } if (! keep_hills) { - hills.erase (hills.begin(), hills.end()); + hills.erase(hills.begin(), hills.end()); } } -void colvarbias_meta::recount_hills_off_grid (colvarbias_meta::hill_iter h_first, +void colvarbias_meta::recount_hills_off_grid(colvarbias_meta::hill_iter h_first, colvarbias_meta::hill_iter h_last, colvar_grid_scalar *he) { hills_off_grid.clear(); for (hill_iter h = h_first; h != h_last; h++) { - cvm::real const min_dist = hills_energy->bin_distance_from_boundaries (h->centers, true); - if (min_dist < (3.0 * std::floor (hill_width)) + 1.0) { - hills_off_grid.push_back (*h); + cvm::real const min_dist = hills_energy->bin_distance_from_boundaries(h->centers, true); + if (min_dist < (3.0 * std::floor(hill_width)) + 1.0) { + hills_off_grid.push_back(*h); } } } // ********************************************************************** // multiple replicas functions // ********************************************************************** void colvarbias_meta::update_replicas_registry() { if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": updating the list of replicas, currently containing "+ - cvm::to_str (replicas.size())+" elements.\n"); + cvm::to_str(replicas.size())+" elements.\n"); { // copy the whole file into a string for convenience - std::string line (""); - std::ifstream reg_file (replicas_registry_file.c_str()); + std::string line(""); + std::ifstream reg_file(replicas_registry_file.c_str()); if (reg_file.good()) { replicas_registry.clear(); - while (colvarparse::getline_nocomments (reg_file, line)) - replicas_registry.append (line+"\n"); + while (colvarparse::getline_nocomments(reg_file, line)) + replicas_registry.append(line+"\n"); } else { - cvm::fatal_error ("Error: failed to open file \""+replicas_registry_file+ + cvm::fatal_error("Error: failed to open file \""+replicas_registry_file+ "\" for reading.\n"); } } // now parse it - std::istringstream reg_is (replicas_registry); + std::istringstream reg_is(replicas_registry); if (reg_is.good()) { - std::string new_replica (""); - std::string new_replica_file (""); + std::string new_replica(""); + std::string new_replica_file(""); while ((reg_is >> new_replica) && new_replica.size() && (reg_is >> new_replica_file) && new_replica_file.size()) { if (new_replica == this->replica_id) { // this is the record for this same replica, skip it if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": skipping this replica's own record: \""+ new_replica+"\", \""+new_replica_file+"\"\n"); new_replica_file.clear(); new_replica.clear(); continue; } bool already_loaded = false; for (size_t ir = 0; ir < replicas.size(); ir++) { if (new_replica == (replicas[ir])->replica_id) { // this replica was already added if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": skipping a replica already loaded, \""+ (replicas[ir])->replica_id+"\".\n"); already_loaded = true; break; } } if (!already_loaded) { // add this replica to the registry - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": accessing replica \""+new_replica+"\".\n"); - replicas.push_back (new colvarbias_meta()); + replicas.push_back(new colvarbias_meta()); (replicas.back())->replica_id = new_replica; (replicas.back())->replica_list_file = new_replica_file; (replicas.back())->replica_state_file = ""; (replicas.back())->replica_state_file_in_sync = false; // Note: the following could become a copy constructor? (replicas.back())->name = this->name; (replicas.back())->colvars = colvars; (replicas.back())->use_grids = use_grids; (replicas.back())->dump_fes = false; (replicas.back())->expand_grids = false; (replicas.back())->rebin_grids = false; (replicas.back())->keep_hills = false; (replicas.back())->colvar_forces = colvar_forces; (replicas.back())->comm = multiple_replicas; if (use_grids) { (replicas.back())->hills_energy = new colvar_grid_scalar (colvars); - (replicas.back())->hills_energy_gradients = new colvar_grid_gradient (colvars); + (replicas.back())->hills_energy_gradients = new colvar_grid_gradient(colvars); } } } } else { - cvm::fatal_error ("Error: cannot read the replicas registry file \""+ + cvm::fatal_error("Error: cannot read the replicas registry file \""+ replicas_registry+"\".\n"); } // now (re)read the list file of each replica for (size_t ir = 0; ir < replicas.size(); ir++) { if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": reading the list file for replica \""+ (replicas[ir])->replica_id+"\".\n"); - std::ifstream list_is ((replicas[ir])->replica_list_file.c_str()); + std::ifstream list_is((replicas[ir])->replica_list_file.c_str()); std::string key; std::string new_state_file, new_hills_file; if (!(list_is >> key) || - !(key == std::string ("stateFile")) || + !(key == std::string("stateFile")) || !(list_is >> new_state_file) || !(list_is >> key) || - !(key == std::string ("hillsFile")) || + !(key == std::string("hillsFile")) || !(list_is >> new_hills_file)) { - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": failed to read the file \""+ (replicas[ir])->replica_list_file+"\": will try again after "+ - cvm::to_str (replica_update_freq)+" steps.\n"); + cvm::to_str(replica_update_freq)+" steps.\n"); (replicas[ir])->update_status++; } else { (replicas[ir])->update_status = 0; if (new_state_file != (replicas[ir])->replica_state_file) { - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": replica \""+(replicas[ir])->replica_id+ "\" has supplied a new state file, \""+new_state_file+ "\".\n"); (replicas[ir])->replica_state_file_in_sync = false; (replicas[ir])->replica_state_file = new_state_file; (replicas[ir])->replica_hills_file = new_hills_file; } } } if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\": the list of replicas contains "+ - cvm::to_str (replicas.size())+" elements.\n"); + cvm::log("Metadynamics bias \""+this->name+"\": the list of replicas contains "+ + cvm::to_str(replicas.size())+" elements.\n"); } void colvarbias_meta::read_replica_files() { for (size_t ir = 0; ir < replicas.size(); ir++) { if (! (replicas[ir])->replica_state_file_in_sync) { // if a new state file is being read, the hills file is also new (replicas[ir])->replica_hills_file_pos = 0; } // (re)read the state file if necessary if ( (! (replicas[ir])->has_data) || (! (replicas[ir])->replica_state_file_in_sync) ) { - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": reading the state of replica \""+ (replicas[ir])->replica_id+"\" from file \""+ (replicas[ir])->replica_state_file+"\".\n"); - std::ifstream is ((replicas[ir])->replica_state_file.c_str()); - if (! (replicas[ir])->read_restart (is)) { - cvm::log ("Reading from file \""+(replicas[ir])->replica_state_file+ + std::ifstream is((replicas[ir])->replica_state_file.c_str()); + if (! (replicas[ir])->read_restart(is)) { + cvm::log("Reading from file \""+(replicas[ir])->replica_state_file+ "\" failed or incomplete: will try again in "+ - cvm::to_str (replica_update_freq)+" steps.\n"); + cvm::to_str(replica_update_freq)+" steps.\n"); } else { // state file has been read successfully (replicas[ir])->replica_state_file_in_sync = true; (replicas[ir])->update_status = 0; } is.close(); } // now read the hills added after writing the state file if ((replicas[ir])->replica_hills_file.size()) { if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": checking for new hills from replica \""+ (replicas[ir])->replica_id+"\" in the file \""+ (replicas[ir])->replica_hills_file+"\".\n"); // read hills from the other replicas' files; for each file, resume // the position recorded previously - std::ifstream is ((replicas[ir])->replica_hills_file.c_str()); + std::ifstream is((replicas[ir])->replica_hills_file.c_str()); if (is.good()) { // try to resume the previous position - is.seekg ((replicas[ir])->replica_hills_file_pos, std::ios::beg); + is.seekg((replicas[ir])->replica_hills_file_pos, std::ios::beg); if (!is.good()){ // if fail (the file may have been overwritten), reset this // position is.clear(); - is.seekg (0, std::ios::beg); + is.seekg(0, std::ios::beg); // reset the counter (replicas[ir])->replica_hills_file_pos = 0; // schedule to reread the state file (replicas[ir])->replica_state_file_in_sync = false; // and record the failure (replicas[ir])->update_status++; - cvm::log ("Failed to read the file \""+(replicas[ir])->replica_hills_file+ + cvm::log("Failed to read the file \""+(replicas[ir])->replica_hills_file+ "\" at the previous position: will try again in "+ - cvm::to_str (replica_update_freq)+" steps.\n"); + cvm::to_str(replica_update_freq)+" steps.\n"); } else { - while ((replicas[ir])->read_hill (is)) { + while ((replicas[ir])->read_hill(is)) { // if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": received a hill from replica \""+ (replicas[ir])->replica_id+ "\" at step "+ - cvm::to_str (((replicas[ir])->hills.back()).it)+".\n"); + cvm::to_str(((replicas[ir])->hills.back()).it)+".\n"); } is.clear(); // store the position for the next read (replicas[ir])->replica_hills_file_pos = is.tellg(); if (cvm::debug()) - cvm::log ("Metadynamics bias \""+this->name+"\""+ + cvm::log("Metadynamics bias \""+this->name+"\""+ ": stopped reading file \""+(replicas[ir])->replica_hills_file+ "\" at position "+ - cvm::to_str ((replicas[ir])->replica_hills_file_pos)+".\n"); + cvm::to_str((replicas[ir])->replica_hills_file_pos)+".\n"); // test whether this is the end of the file - is.seekg (0, std::ios::end); + is.seekg(0, std::ios::end); if (is.tellg() > (replicas[ir])->replica_hills_file_pos+1) { (replicas[ir])->update_status++; } else { (replicas[ir])->update_status = 0; } } } else { - cvm::log ("Failed to read the file \""+(replicas[ir])->replica_hills_file+ + cvm::log("Failed to read the file \""+(replicas[ir])->replica_hills_file+ "\": will try again in "+ - cvm::to_str (replica_update_freq)+" steps.\n"); + cvm::to_str(replica_update_freq)+" steps.\n"); (replicas[ir])->update_status++; // cvm::fatal_error ("Error: cannot read from file \""+ // (replicas[ir])->replica_hills_file+"\".\n"); } is.close(); } size_t const n_flush = (replica_update_freq/new_hill_freq + 1); if ((replicas[ir])->update_status > 3*n_flush) { // TODO: suspend the calculation? - cvm::log ("WARNING: in metadynamics bias \""+this->name+"\""+ + cvm::log("WARNING: in metadynamics bias \""+this->name+"\""+ " failed to read completely the output of replica \""+ (replicas[ir])->replica_id+ "\" after more than "+ - cvm::to_str ((replicas[ir])->update_status * replica_update_freq)+ + cvm::to_str((replicas[ir])->update_status * replica_update_freq)+ " steps. Ensure that it is still running.\n"); } } } // ********************************************************************** // input functions // ********************************************************************** -std::istream & colvarbias_meta::read_restart (std::istream& is) +std::istream & colvarbias_meta::read_restart(std::istream& is) { size_t const start_pos = is.tellg(); if (comm == single_replica) { // if using a multiple replicas scheme, output messages // are printed before and after calling this function - cvm::log ("Restarting metadynamics bias \""+this->name+"\""+ + cvm::log("Restarting metadynamics bias \""+this->name+"\""+ ".\n"); } std::string key, brace, conf; if ( !(is >> key) || !(key == "metadynamics") || !(is >> brace) || !(brace == "{") || - !(is >> colvarparse::read_block ("configuration", conf)) ) { + !(is >> colvarparse::read_block("configuration", conf)) ) { if (comm == single_replica) - cvm::log ("Error: in reading restart configuration for metadynamics bias \""+ + cvm::log("Error: in reading restart configuration for metadynamics bias \""+ this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ (replica_state_file_in_sync ? ("at position "+ - cvm::to_str (start_pos)+ + cvm::to_str(start_pos)+ " in the state file") : "")+".\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } std::string name = ""; - if ( colvarparse::get_keyval (conf, "name", name, - std::string (""), colvarparse::parse_silent) && + if ( colvarparse::get_keyval(conf, "name", name, + std::string(""), colvarparse::parse_silent) && (name != this->name) ) - cvm::fatal_error ("Error: in the restart file, the " + cvm::fatal_error("Error: in the restart file, the " "\"metadynamics\" block has a different name: different system?\n"); if (name.size() == 0) { - cvm::fatal_error ("Error: \"metadynamics\" block within the restart file " + cvm::fatal_error("Error: \"metadynamics\" block within the restart file " "has no identifiers.\n"); } if (comm != single_replica) { std::string replica = ""; - if (colvarparse::get_keyval (conf, "replicaID", replica, - std::string (""), colvarparse::parse_silent) && + if (colvarparse::get_keyval(conf, "replicaID", replica, + std::string(""), colvarparse::parse_silent) && (replica != this->replica_id)) - cvm::fatal_error ("Error: in the restart file, the " + cvm::fatal_error("Error: in the restart file, the " "\"metadynamics\" block has a different replicaID: different system?\n"); - colvarparse::get_keyval (conf, "step", state_file_step, + colvarparse::get_keyval(conf, "step", state_file_step, cvm::step_absolute(), colvarparse::parse_silent); } bool grids_from_restart_file = use_grids; if (use_grids) { if (expand_grids) { // the boundaries of the colvars may have been changed; TODO: // this reallocation is only for backward-compatibility, and may // be deleted when grid_parameters (i.e. colvargrid's own // internal reallocation) has kicked in delete hills_energy; delete hills_energy_gradients; - hills_energy = new colvar_grid_scalar (colvars); - hills_energy_gradients = new colvar_grid_gradient (colvars); + hills_energy = new colvar_grid_scalar(colvars); + hills_energy_gradients = new colvar_grid_gradient(colvars); } colvar_grid_scalar *hills_energy_backup = NULL; colvar_grid_gradient *hills_energy_gradients_backup = NULL; if (has_data) { if (cvm::debug()) - cvm::log ("Backupping grids for metadynamics bias \""+ + cvm::log("Backupping grids for metadynamics bias \""+ this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n"); hills_energy_backup = hills_energy; hills_energy_gradients_backup = hills_energy_gradients; - hills_energy = new colvar_grid_scalar (colvars); - hills_energy_gradients = new colvar_grid_gradient (colvars); + hills_energy = new colvar_grid_scalar(colvars); + hills_energy_gradients = new colvar_grid_gradient(colvars); } size_t const hills_energy_pos = is.tellg(); if (!(is >> key)) { if (hills_energy_backup != NULL) { delete hills_energy; delete hills_energy_gradients; hills_energy = hills_energy_backup; hills_energy_gradients = hills_energy_gradients_backup; } is.clear(); - is.seekg (hills_energy_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(hills_energy_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; - } else if (!(key == std::string ("hills_energy")) || - !(hills_energy->read_restart (is))) { + } else if (!(key == std::string("hills_energy")) || + !(hills_energy->read_restart(is))) { is.clear(); - is.seekg (hills_energy_pos, std::ios::beg); + is.seekg(hills_energy_pos, std::ios::beg); grids_from_restart_file = false; if (!rebin_grids) { if (hills_energy_backup == NULL) - cvm::fatal_error ("Error: couldn't read the free energy grid for metadynamics bias \""+ + cvm::fatal_error("Error: couldn't read the free energy grid for metadynamics bias \""+ this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ "; if useGrids was off when the state file was written, " "enable rebinGrids now to regenerate the grids.\n"); else { if (comm == single_replica) - cvm::log ("Error: couldn't read the free energy grid for metadynamics bias \""+ + cvm::log("Error: couldn't read the free energy grid for metadynamics bias \""+ this->name+"\".\n"); delete hills_energy; delete hills_energy_gradients; hills_energy = hills_energy_backup; hills_energy_gradients = hills_energy_gradients_backup; - is.setstate (std::ios::failbit); + is.setstate(std::ios::failbit); return is; } } } size_t const hills_energy_gradients_pos = is.tellg(); if (!(is >> key)) { if (hills_energy_backup != NULL) { delete hills_energy; delete hills_energy_gradients; hills_energy = hills_energy_backup; hills_energy_gradients = hills_energy_gradients_backup; } is.clear(); - is.seekg (hills_energy_gradients_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(hills_energy_gradients_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; - } else if (!(key == std::string ("hills_energy_gradients")) || - !(hills_energy_gradients->read_restart (is))) { + } else if (!(key == std::string("hills_energy_gradients")) || + !(hills_energy_gradients->read_restart(is))) { is.clear(); - is.seekg (hills_energy_gradients_pos, std::ios::beg); + is.seekg(hills_energy_gradients_pos, std::ios::beg); grids_from_restart_file = false; if (!rebin_grids) { if (hills_energy_backup == NULL) - cvm::fatal_error ("Error: couldn't read the free energy gradients grid for metadynamics bias \""+ + cvm::fatal_error("Error: couldn't read the free energy gradients grid for metadynamics bias \""+ this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ "; if useGrids was off when the state file was written, " "enable rebinGrids now to regenerate the grids.\n"); else { if (comm == single_replica) - cvm::log ("Error: couldn't read the free energy gradients grid for metadynamics bias \""+ + cvm::log("Error: couldn't read the free energy gradients grid for metadynamics bias \""+ this->name+"\".\n"); delete hills_energy; delete hills_energy_gradients; hills_energy = hills_energy_backup; hills_energy_gradients = hills_energy_gradients_backup; - is.setstate (std::ios::failbit); + is.setstate(std::ios::failbit); return is; } } } if (cvm::debug()) - cvm::log ("Successfully read new grids for bias \""+ + cvm::log("Successfully read new grids for bias \""+ this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n"); if (hills_energy_backup != NULL) { // now that we have successfully updated the grids, delete the // backup copies if (cvm::debug()) - cvm::log ("Deallocating the older grids.\n"); + cvm::log("Deallocating the older grids.\n"); delete hills_energy_backup; delete hills_energy_gradients_backup; } } bool const existing_hills = !hills.empty(); size_t const old_hills_size = hills.size(); hill_iter old_hills_end = hills.end(); hill_iter old_hills_off_grid_end = hills_off_grid.end(); // read the hills explicitly written (if there are any) - while (read_hill (is)) { + while (read_hill(is)) { if (cvm::debug()) - cvm::log ("Read a previously saved hill under the " + cvm::log("Read a previously saved hill under the " "metadynamics bias \""+ this->name+"\", created at step "+ - cvm::to_str ((hills.back()).it)+".\n"); + cvm::to_str((hills.back()).it)+".\n"); } is.clear(); new_hills_begin = hills.end(); if (grids_from_restart_file) { if (hills.size() > old_hills_size) - cvm::log ("Read "+cvm::to_str (hills.size())+ + cvm::log("Read "+cvm::to_str(hills.size())+ " hills in addition to the grids.\n"); } else { if (!hills.empty()) - cvm::log ("Read "+cvm::to_str (hills.size())+" hills.\n"); + cvm::log("Read "+cvm::to_str(hills.size())+" hills.\n"); } if (rebin_grids) { // allocate new grids (based on the new boundaries and widths just // read from the configuration file), and project onto them the // grids just read from the restart file colvar_grid_scalar *new_hills_energy = - new colvar_grid_scalar (colvars); + new colvar_grid_scalar(colvars); colvar_grid_gradient *new_hills_energy_gradients = - new colvar_grid_gradient (colvars); + new colvar_grid_gradient(colvars); if (!grids_from_restart_file || (keep_hills && !hills.empty())) { // if there are hills, recompute the new grids from them - cvm::log ("Rebinning the energy and forces grids from "+ - cvm::to_str (hills.size())+" hills (this may take a while)...\n"); - project_hills (hills.begin(), hills.end(), + cvm::log("Rebinning the energy and forces grids from "+ + cvm::to_str(hills.size())+" hills (this may take a while)...\n"); + project_hills(hills.begin(), hills.end(), new_hills_energy, new_hills_energy_gradients, true); - cvm::log ("rebinning done.\n"); + cvm::log("rebinning done.\n"); } else { // otherwise, use the grids in the restart file - cvm::log ("Rebinning the energy and forces grids " + cvm::log("Rebinning the energy and forces grids " "from the grids in the restart file.\n"); - new_hills_energy->map_grid (*hills_energy); - new_hills_energy_gradients->map_grid (*hills_energy_gradients); + new_hills_energy->map_grid(*hills_energy); + new_hills_energy_gradients->map_grid(*hills_energy_gradients); } delete hills_energy; delete hills_energy_gradients; hills_energy = new_hills_energy; hills_energy_gradients = new_hills_energy_gradients; // assuming that some boundaries have expanded, eliminate those // off-grid hills that aren't necessary any more if (!hills.empty()) - recount_hills_off_grid (hills.begin(), hills.end(), hills_energy); + recount_hills_off_grid(hills.begin(), hills.end(), hills_energy); } if (use_grids) { if (!hills_off_grid.empty()) { - cvm::log (cvm::to_str (hills_off_grid.size())+" hills are near the " + cvm::log(cvm::to_str(hills_off_grid.size())+" hills are near the " "grid boundaries: they will be computed analytically " "and saved to the state files.\n"); } } is >> brace; if (brace != "}") { - cvm::log ("Incomplete restart information for metadynamics bias \""+ + cvm::log("Incomplete restart information for metadynamics bias \""+ this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ ": no closing brace at position "+ - cvm::to_str (is.tellg())+" in the file.\n"); - is.setstate (std::ios::failbit); + cvm::to_str(is.tellg())+" in the file.\n"); + is.setstate(std::ios::failbit); return is; } if (cvm::debug()) - cvm::log ("colvarbias_meta::read_restart() done\n"); + cvm::log("colvarbias_meta::read_restart() done\n"); if (existing_hills) { - hills.erase (hills.begin(), old_hills_end); - hills_off_grid.erase (hills_off_grid.begin(), old_hills_off_grid_end); + hills.erase(hills.begin(), old_hills_end); + hills_off_grid.erase(hills_off_grid.begin(), old_hills_off_grid_end); } has_data = true; if (comm != single_replica) { read_replica_files(); } return is; } -std::istream & colvarbias_meta::read_hill (std::istream &is) +std::istream & colvarbias_meta::read_hill(std::istream &is) { if (!is) return is; // do nothing if failbit is set size_t const start_pos = is.tellg(); std::string data; - if ( !(is >> read_block ("hill", data)) ) { + if ( !(is >> read_block("hill", data)) ) { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } size_t h_it; - get_keyval (data, "step", h_it, 0, parse_silent); + get_keyval(data, "step", h_it, 0, parse_silent); if (h_it <= state_file_step) { if (cvm::debug()) - cvm::log ("Skipping a hill older than the state file for metadynamics bias \""+ + cvm::log("Skipping a hill older than the state file for metadynamics bias \""+ this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+"\n"); return is; } cvm::real h_weight; - get_keyval (data, "weight", h_weight, hill_weight, parse_silent); + get_keyval(data, "weight", h_weight, hill_weight, parse_silent); - std::vector h_centers (colvars.size()); + std::vector h_centers(colvars.size()); for (size_t i = 0; i < colvars.size(); i++) { - h_centers[i].type ((colvars[i]->value()).type()); + h_centers[i].type(colvars[i]->value()); } { // it is safer to read colvarvalue objects one at a time; // TODO: change this it later std::string centers_input; - key_lookup (data, "centers", centers_input); - std::istringstream centers_is (centers_input); + key_lookup(data, "centers", centers_input); + std::istringstream centers_is(centers_input); for (size_t i = 0; i < colvars.size(); i++) { centers_is >> h_centers[i]; } } - std::vector h_widths (colvars.size()); - get_keyval (data, "widths", h_widths, - std::vector (colvars.size(), (std::sqrt (2.0 * PI) / 2.0)), + std::vector h_widths(colvars.size()); + get_keyval(data, "widths", h_widths, + std::vector (colvars.size(), (std::sqrt(2.0 * PI) / 2.0)), parse_silent); std::string h_replica = ""; if (comm != single_replica) { - get_keyval (data, "replicaID", h_replica, replica_id, parse_silent); + get_keyval(data, "replicaID", h_replica, replica_id, parse_silent); if (h_replica != replica_id) - cvm::fatal_error ("Error: trying to read a hill created by replica \""+h_replica+ + cvm::fatal_error("Error: trying to read a hill created by replica \""+h_replica+ "\" for replica \""+replica_id+ "\"; did you swap output files?\n"); } hill_iter const hills_end = hills.end(); - hills.push_back (hill (h_it, h_weight, h_centers, h_widths, h_replica)); + hills.push_back(hill(h_it, h_weight, h_centers, h_widths, h_replica)); if (new_hills_begin == hills_end) { // if new_hills_begin is unset, set it for the first time new_hills_begin = hills.end(); new_hills_begin--; } if (use_grids) { // add this also to the list of hills that are off-grid, which will // be computed analytically cvm::real const min_dist = - hills_energy->bin_distance_from_boundaries ((hills.back()).centers, true); - if (min_dist < (3.0 * std::floor (hill_width)) + 1.0) { - hills_off_grid.push_back (hills.back()); + hills_energy->bin_distance_from_boundaries((hills.back()).centers, true); + if (min_dist < (3.0 * std::floor(hill_width)) + 1.0) { + hills_off_grid.push_back(hills.back()); } } has_data = true; return is; } // ********************************************************************** // output functions // ********************************************************************** -std::ostream & colvarbias_meta::write_restart (std::ostream& os) +std::ostream & colvarbias_meta::write_restart(std::ostream& os) { os << "metadynamics {\n" << " configuration {\n" << " step " << cvm::step_absolute() << "\n" << " name " << this->name << "\n"; if (this->comm != single_replica) os << " replicaID " << this->replica_id << "\n"; os << " }\n\n"; if (use_grids) { // this is a very good time to project hills, if you haven't done // it already! - project_hills (new_hills_begin, hills.end(), + project_hills(new_hills_begin, hills.end(), hills_energy, hills_energy_gradients); new_hills_begin = hills.end(); // write down the grids to the restart file os << " hills_energy\n"; - hills_energy->write_restart (os); + hills_energy->write_restart(os); os << " hills_energy_gradients\n"; - hills_energy_gradients->write_restart (os); + hills_energy_gradients->write_restart(os); } if ( (!use_grids) || keep_hills ) { // write all hills currently in memory for (std::list::const_iterator h = this->hills.begin(); h != this->hills.end(); h++) { os << *h; } } else { // write just those that are near the grid boundaries for (std::list::const_iterator h = this->hills_off_grid.begin(); h != this->hills_off_grid.end(); h++) { os << *h; } } os << "}\n\n"; if (comm != single_replica) { write_replica_state_file(); // schedule to reread the state files of the other replicas (they // have also rewritten them) for (size_t ir = 0; ir < replicas.size(); ir++) { (replicas[ir])->replica_state_file_in_sync = false; } } if (dump_fes) { write_pmf(); } return os; } void colvarbias_meta::write_pmf() { // allocate a new grid to store the pmf - colvar_grid_scalar *pmf = new colvar_grid_scalar (*hills_energy); + colvar_grid_scalar *pmf = new colvar_grid_scalar(*hills_energy); pmf->create(); - std::string fes_file_name_prefix (cvm::output_prefix); + std::string fes_file_name_prefix(cvm::output_prefix); if ((cvm::n_meta_biases > 1) || (cvm::n_abf_biases > 0)) { // if this is not the only free energy integrator, append // this bias's name, to distinguish it from the output of the other // biases producing a .pmf file // TODO: fix for ABF with updateBias == no fes_file_name_prefix += ("."+this->name); } if ((comm == single_replica) || (dump_replica_fes)) { // output the PMF from this instance or replica pmf->reset(); - pmf->add_grid (*hills_energy); + pmf->add_grid(*hills_energy); cvm::real const max = pmf->maximum_value(); - pmf->add_constant (-1.0 * max); - pmf->multiply_constant (-1.0); + pmf->add_constant(-1.0 * max); + pmf->multiply_constant(-1.0); if (well_tempered) { cvm::real const well_temper_scale = (bias_temperature + cvm::temperature()) / bias_temperature; - pmf->multiply_constant (well_temper_scale); + pmf->multiply_constant(well_temper_scale); } { - std::string const fes_file_name (fes_file_name_prefix + + std::string const fes_file_name(fes_file_name_prefix + ((comm != single_replica) ? ".partial" : "") + (dump_fes_save ? - "."+cvm::to_str (cvm::step_absolute()) : "") + + "."+cvm::to_str(cvm::step_absolute()) : "") + ".pmf"); - cvm::backup_file (fes_file_name.c_str()); - std::ofstream fes_os (fes_file_name.c_str()); - pmf->write_multicol (fes_os); + cvm::backup_file(fes_file_name.c_str()); + std::ofstream fes_os(fes_file_name.c_str()); + pmf->write_multicol(fes_os); fes_os.close(); } } if (comm != single_replica) { // output the combined PMF from all replicas pmf->reset(); - pmf->add_grid (*hills_energy); + pmf->add_grid(*hills_energy); for (size_t ir = 0; ir < replicas.size(); ir++) { - pmf->add_grid (*(replicas[ir]->hills_energy)); + pmf->add_grid(*(replicas[ir]->hills_energy)); } cvm::real const max = pmf->maximum_value(); - pmf->add_constant (-1.0 * max); - pmf->multiply_constant (-1.0); + pmf->add_constant(-1.0 * max); + pmf->multiply_constant(-1.0); if (well_tempered) { cvm::real const well_temper_scale = (bias_temperature + cvm::temperature()) / bias_temperature; - pmf->multiply_constant (well_temper_scale); + pmf->multiply_constant(well_temper_scale); } - std::string const fes_file_name (fes_file_name_prefix + + std::string const fes_file_name(fes_file_name_prefix + (dump_fes_save ? - "."+cvm::to_str (cvm::step_absolute()) : "") + + "."+cvm::to_str(cvm::step_absolute()) : "") + ".pmf"); - cvm::backup_file (fes_file_name.c_str()); - std::ofstream fes_os (fes_file_name.c_str()); - pmf->write_multicol (fes_os); + cvm::backup_file(fes_file_name.c_str()); + std::ofstream fes_os(fes_file_name.c_str()); + pmf->write_multicol(fes_os); fes_os.close(); } delete pmf; } void colvarbias_meta::write_replica_state_file() { // write down also the restart for the other replicas: TODO: this // is duplicated code, that could be cleaned up later - cvm::backup_file (replica_state_file.c_str()); - std::ofstream rep_state_os (replica_state_file.c_str()); + cvm::backup_file(replica_state_file.c_str()); + std::ofstream rep_state_os(replica_state_file.c_str()); if (!rep_state_os.good()) - cvm::fatal_error ("Error: in opening file \""+ + cvm::fatal_error("Error: in opening file \""+ replica_state_file+"\" for writing.\n"); - rep_state_os.setf (std::ios::scientific, std::ios::floatfield); + rep_state_os.setf(std::ios::scientific, std::ios::floatfield); rep_state_os << "\n" << "metadynamics {\n" << " configuration {\n" << " name " << this->name << "\n" << " step " << cvm::step_absolute() << "\n"; if (this->comm != single_replica) { rep_state_os << " replicaID " << this->replica_id << "\n"; } rep_state_os << " }\n\n"; rep_state_os << " hills_energy\n"; - rep_state_os << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width); - hills_energy->write_restart (rep_state_os); + rep_state_os << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width); + hills_energy->write_restart(rep_state_os); rep_state_os << " hills_energy_gradients\n"; - rep_state_os << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width); - hills_energy_gradients->write_restart (rep_state_os); + rep_state_os << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width); + hills_energy_gradients->write_restart(rep_state_os); if ( (!use_grids) || keep_hills ) { // write all hills currently in memory for (std::list::const_iterator h = this->hills.begin(); h != this->hills.end(); h++) { rep_state_os << *h; } } else { // write just those that are near the grid boundaries for (std::list::const_iterator h = this->hills_off_grid.begin(); h != this->hills_off_grid.end(); h++) { rep_state_os << *h; } } rep_state_os << "}\n\n"; rep_state_os.close(); // reopen the hills file replica_hills_os.close(); - replica_hills_os.open (replica_hills_file.c_str()); + replica_hills_os.open(replica_hills_file.c_str()); if (!replica_hills_os.good()) - cvm::fatal_error ("Error: in opening file \""+ + cvm::fatal_error("Error: in opening file \""+ replica_hills_file+"\" for writing.\n"); - replica_hills_os.setf (std::ios::scientific, std::ios::floatfield); + replica_hills_os.setf(std::ios::scientific, std::ios::floatfield); } std::string colvarbias_meta::hill::output_traj() { std::ostringstream os; - os.setf (std::ios::fixed, std::ios::floatfield); - os << std::setw (cvm::it_width) << it << " "; + os.setf(std::ios::fixed, std::ios::floatfield); + os << std::setw(cvm::it_width) << it << " "; - os.setf (std::ios::scientific, std::ios::floatfield); + os.setf(std::ios::scientific, std::ios::floatfield); size_t i; os << " "; for (i = 0; i < centers.size(); i++) { os << " "; - os << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) << centers[i]; + os << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << centers[i]; } os << " "; for (i = 0; i < widths.size(); i++) { os << " "; - os << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) << widths[i]; + os << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << widths[i]; } os << " "; - os << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << W << "\n"; + os << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << W << "\n"; return os.str(); } std::ostream & operator << (std::ostream &os, colvarbias_meta::hill const &h) { - os.setf (std::ios::scientific, std::ios::floatfield); + os.setf(std::ios::scientific, std::ios::floatfield); os << "hill {\n"; - os << " step " << std::setw (cvm::it_width) << h.it << "\n"; + os << " step " << std::setw(cvm::it_width) << h.it << "\n"; os << " weight " - << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) + << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << h.W << "\n"; if (h.replica.size()) os << " replicaID " << h.replica << "\n"; size_t i; os << " centers "; for (i = 0; i < (h.centers).size(); i++) { os << " " - << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << h.centers[i]; } os << "\n"; os << " widths "; for (i = 0; i < (h.widths).size(); i++) { os << " " - << std::setprecision (cvm::cv_prec) - << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) << h.widths[i]; } os << "\n"; os << "}\n"; return os; } + + diff --git a/lib/colvars/colvarbias_meta.h b/lib/colvars/colvarbias_meta.h index 42faac9d5..de5b6d262 100644 --- a/lib/colvars/colvarbias_meta.h +++ b/lib/colvars/colvarbias_meta.h @@ -1,421 +1,421 @@ /// -*- c++ -*- #ifndef COLVARBIAS_META_H #define COLVARBIAS_META_H #include #include #include #include #include "colvarbias.h" #include "colvargrid.h" /// Metadynamics bias (implementation of \link colvarbias \endlink) class colvarbias_meta : public colvarbias { public: /// Communication between different replicas enum Communication { /// One replica (default) single_replica, /// Hills added concurrently by several replicas multiple_replicas }; /// Communication between different replicas Communication comm; /// Constructor - colvarbias_meta (std::string const &conf, char const *key); + colvarbias_meta(std::string const &conf, char const *key); /// Default constructor colvarbias_meta(); /// Destructor virtual ~colvarbias_meta(); virtual cvm::real update(); - virtual std::istream & read_restart (std::istream &is); + virtual std::istream & read_restart(std::istream &is); - virtual std::ostream & write_restart (std::ostream &os); + virtual std::ostream & write_restart(std::ostream &os); virtual void write_pmf(); class hill; typedef std::list::iterator hill_iter; protected: /// \brief width of a hill /// /// The local width of each collective variable, multiplied by this /// number, provides the hill width along that direction cvm::real hill_width; /// \brief Number of simulation steps between two hills size_t new_hill_freq; /// Write the hill logfile bool b_hills_traj; /// Logfile of hill management (creation and deletion) std::ofstream hills_traj_os; /// \brief List of hills used on this bias (total); if a grid is /// employed, these don't need to be updated at every time step std::list hills; /// \brief Iterator to the first of the "newest" hills (when using /// grids, those who haven't been mapped yet) hill_iter new_hills_begin; /// \brief List of hills used on this bias that are on the boundary /// edges; these are updated regardless of whether hills are used std::list hills_off_grid; /// \brief Same as new_hills_begin, but for the off-grid ones hill_iter new_hills_off_grid_begin; /// Regenerate the hills_off_grid list - void recount_hills_off_grid (hill_iter h_first, hill_iter h_last, + void recount_hills_off_grid(hill_iter h_first, hill_iter h_last, colvar_grid_scalar *ge); /// Read a hill from a file - std::istream & read_hill (std::istream &is); + std::istream & read_hill(std::istream &is); /// \brief step present in a state file /// /// When using grids and reading state files containing them /// (multiple replicas), this is used to check whether a hill is /// newer or older than the grids size_t state_file_step; /// \brief Add a new hill; if a .hills trajectory is written, /// write it there; if there is more than one replica, communicate /// it to the others - virtual std::list::const_iterator create_hill (hill const &h); + virtual std::list::const_iterator create_hill(hill const &h); /// \brief Remove a previously saved hill (returns an iterator for /// the next hill in the list) - virtual std::list::const_iterator delete_hill (hill_iter &h); + virtual std::list::const_iterator delete_hill(hill_iter &h); /// \brief Calculate the values of the hills, incrementing /// bias_energy - virtual void calc_hills (hill_iter h_first, + virtual void calc_hills(hill_iter h_first, hill_iter h_last, cvm::real &energy, std::vector const &values = std::vector (0)); /// \brief Calculate the forces acting on the i-th colvar, /// incrementing colvar_forces[i]; must be called after calc_hills /// each time the values of the colvars are changed - virtual void calc_hills_force (size_t const &i, + virtual void calc_hills_force(size_t const &i, hill_iter h_first, hill_iter h_last, std::vector &forces, std::vector const &values = std::vector (0)); /// Height of new hills cvm::real hill_weight; /// \brief Bin the hills on grids of energy and forces, and use them /// to force the colvars (as opposed to deriving the hills analytically) bool use_grids; /// \brief Rebin the hills upon restarting bool rebin_grids; /// \brief Should the grids be expanded if necessary? bool expand_grids; /// \brief How often the hills should be projected onto the grids size_t grids_freq; /// \brief Whether to keep the hills in the restart file (e.g. to do /// meaningful accurate rebinning afterwards) bool keep_hills; /// \brief Dump the free energy surface (.pmf file) every restartFrequency bool dump_fes; /// \brief Dump the free energy surface (.pmf file) every restartFrequency /// using only the hills from this replica (only applicable to more than one replica) bool dump_replica_fes; /// \brief Dump the free energy surface files at different /// time steps, appending the step number to each file bool dump_fes_save; /// \brief Whether to use well-tempered metadynamics bool well_tempered; /// \brief Biasing temperature in well-tempered metadynamics cvm::real bias_temperature; /// \brief Try to read the restart information by allocating new /// grids before replacing the current ones (used e.g. in /// multiple_replicas) bool safely_read_restart; /// Hill energy, cached on a grid colvar_grid_scalar *hills_energy; /// Hill forces, cached on a grid colvar_grid_gradient *hills_energy_gradients; /// \brief Project the selected hills onto grids - void project_hills (hill_iter h_first, hill_iter h_last, + void project_hills(hill_iter h_first, hill_iter h_last, colvar_grid_scalar *ge, colvar_grid_gradient *gf, bool print_progress = false); // Multiple Replicas variables and functions /// \brief Identifier for this replica std::string replica_id; /// \brief File containing the paths to the output files from this replica std::string replica_file_name; /// \brief Read the existing replicas on registry virtual void update_replicas_registry(); /// \brief Read new data from replicas' files virtual void read_replica_files(); /// \brief Write data to other replicas virtual void write_replica_state_file(); /// \brief Additional, "mirror" metadynamics biases, to collect info /// from the other replicas /// /// These are supposed to be synchronized by reading data from the /// other replicas, and not be modified by the "local" replica std::vector replicas; /// \brief Frequency at which data the "mirror" biases are updated size_t replica_update_freq; /// List of replicas (and their output list files): contents are /// copied into replicas_registry for convenience std::string replicas_registry_file; /// List of replicas (and their output list files) std::string replicas_registry; /// List of files written by this replica std::string replica_list_file; /// Hills energy and gradients written specifically for other /// replica (in addition to its own restart file) std::string replica_state_file; /// Whether a mirror bias has read the latest version of its state file bool replica_state_file_in_sync; /// If there was a failure reading one of the files (because they /// are not complete), this counter is incremented size_t update_status; /// Explicit hills communicated between replicas /// /// This file becomes empty after replica_state_file is rewritten std::string replica_hills_file; /// \brief Output stream corresponding to replica_hills_file std::ofstream replica_hills_os; /// Position within replica_hills_file (when reading it) int replica_hills_file_pos; }; /// \brief A hill for the metadynamics bias class colvarbias_meta::hill { protected: /// Value of the hill function (ranges between 0 and 1) cvm::real hill_value; /// Scale factor, which could be modified at runtime (default: 1) cvm::real sW; /// Maximum height in energy of the hill cvm::real W; /// Center of the hill in the collective variable space std::vector centers; /// Widths of the hill in the collective variable space std::vector widths; public: friend class colvarbias_meta; /// Time step at which this hill was added size_t it; /// Identity of the replica who added this hill (only in multiple replica simulations) std::string replica; /// \brief Runtime constructor: data are read directly from /// collective variables \param weight Weight of the hill \param /// cv Pointer to the array of collective variables involved \param /// replica (optional) Identity of the replica which creates the /// hill - inline hill (cvm::real const &W_in, + inline hill(cvm::real const &W_in, std::vector &cv, cvm::real const &hill_width, std::string const &replica_in = "") - : sW (1.0), - W (W_in), - centers (cv.size()), - widths (cv.size()), - it (cvm::it), - replica (replica_in) + : sW(1.0), + W(W_in), + centers(cv.size()), + widths(cv.size()), + it(cvm::it), + replica(replica_in) { for (size_t i = 0; i < cv.size(); i++) { - centers[i].type (cv[i]->type()); + centers[i].type(cv[i]->value()); centers[i] = cv[i]->value(); widths[i] = cv[i]->width * hill_width; } if (cvm::debug()) - cvm::log ("New hill, applied to "+cvm::to_str (cv.size())+ + cvm::log("New hill, applied to "+cvm::to_str(cv.size())+ " collective variables, with centers "+ - cvm::to_str (centers)+", widths "+ - cvm::to_str (widths)+" and weight "+ - cvm::to_str (W)+".\n"); + cvm::to_str(centers)+", widths "+ + cvm::to_str(widths)+" and weight "+ + cvm::to_str(W)+".\n"); } /// \brief General constructor: all data are explicitly passed as /// arguments (used for instance when reading hills saved on a /// file) \param it Time step of creation of the hill \param /// weight Weight of the hill \param centers Center of the hill /// \param widths Width of the hill around centers \param replica /// (optional) Identity of the replica which creates the hill - inline hill (size_t const &it_in, + inline hill(size_t const &it_in, cvm::real const &W_in, std::vector const ¢ers_in, std::vector const &widths_in, std::string const &replica_in = "") - : sW (1.0), - W (W_in), - centers (centers_in), - widths (widths_in), - it (it_in), - replica (replica_in) + : sW(1.0), + W(W_in), + centers(centers_in), + widths(widths_in), + it(it_in), + replica(replica_in) {} /// Copy constructor - inline hill (colvarbias_meta::hill const &h) - : sW (1.0), - W (h.W), - centers (h.centers), - widths (h.widths), - it (h.it), - replica (h.replica) + inline hill(colvarbias_meta::hill const &h) + : sW(1.0), + W(h.W), + centers(h.centers), + widths(h.widths), + it(h.it), + replica(h.replica) {} /// Destructor inline ~hill() {} /// Get the energy inline cvm::real energy() { return W * sW * hill_value; } /// Get the energy using another hill weight - inline cvm::real energy (cvm::real const &new_weight) + inline cvm::real energy(cvm::real const &new_weight) { return new_weight * sW * hill_value; } /// Get the current hill value inline cvm::real const &value() { return hill_value; } /// Set the hill value as specified - inline void value (cvm::real const &new_value) + inline void value(cvm::real const &new_value) { hill_value = new_value; } /// Get the weight inline cvm::real weight() { return W * sW; } /// Scale the weight with this factor (by default 1.0 is used) - inline void scale (cvm::real const &new_scale_fac) + inline void scale(cvm::real const &new_scale_fac) { sW = new_scale_fac; } /// Get the center of the hill inline std::vector & center() { return centers; } /// Get the i-th component of the center - inline colvarvalue & center (size_t const &i) + inline colvarvalue & center(size_t const &i) { return centers[i]; } /// Comparison operator inline friend bool operator < (hill const &h1, hill const &h2) { if (h1.it < h2.it) return true; else return false; } /// Comparison operator inline friend bool operator <= (hill const &h1, hill const &h2) { if (h1.it <= h2.it) return true; else return false; } /// Comparison operator inline friend bool operator > (hill const &h1, hill const &h2) { if (h1.it > h2.it) return true; else return false; } /// Comparison operator inline friend bool operator >= (hill const &h1, hill const &h2) { if (h1.it >= h2.it) return true; else return false; } /// Comparison operator inline friend bool operator == (hill const &h1, hill const &h2) { if ( (h1.it >= h2.it) && (h1.replica == h2.replica) ) return true; else return false; } /// Represent the hill ina string suitable for a trajectory file std::string output_traj(); /// Write the hill to an output stream inline friend std::ostream & operator << (std::ostream &os, hill const &h); }; #endif diff --git a/lib/colvars/colvarbias_restraint.cpp b/lib/colvars/colvarbias_restraint.cpp index f5e2ae8e7..76586291e 100644 --- a/lib/colvars/colvarbias_restraint.cpp +++ b/lib/colvars/colvarbias_restraint.cpp @@ -1,530 +1,553 @@ /// -*- c++ -*- #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarbias_restraint.h" -colvarbias_restraint::colvarbias_restraint (std::string const &conf, - char const *key) - : colvarbias (conf, key), - target_nstages (0), - target_nsteps (0) +colvarbias_restraint::colvarbias_restraint(std::string const &conf, + char const *key) + : colvarbias(conf, key), + target_nstages(0), + target_nsteps(0) { - get_keyval (conf, "forceConstant", force_k, 1.0); + get_keyval(conf, "forceConstant", force_k, 1.0); - // get the initial restraint centers - colvar_centers.resize (colvars.size()); - colvar_centers_raw.resize (colvars.size()); - for (size_t i = 0; i < colvars.size(); i++) { - colvar_centers[i].type (colvars[i]->type()); - colvar_centers_raw[i].type (colvars[i]->type()); - } - if (get_keyval (conf, "centers", colvar_centers, colvar_centers)) { - for (size_t i = 0; i < colvars.size(); i++) { - colvar_centers[i].apply_constraints(); - colvar_centers_raw[i] = colvar_centers[i]; + { + // get the initial restraint centers + colvar_centers.resize(colvars.size()); + colvar_centers_raw.resize(colvars.size()); + size_t i; + for (i = 0; i < colvars.size(); i++) { + colvar_centers[i].type(colvars[i]->value()); + colvar_centers_raw[i].type(colvars[i]->value()); + if (cvm::debug()) { + cvm::log("colvarbias_restraint: center size = "+ + cvm::to_str(colvar_centers[i].vector1d_value.size())+"\n"); + } + } + if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) { + for (i = 0; i < colvars.size(); i++) { + if (cvm::debug()) { + cvm::log("colvarbias_restraint: parsing initial centers, i = "+cvm::to_str(i)+".\n"); + } + + colvar_centers[i].apply_constraints(); + colvar_centers_raw[i] = colvar_centers[i]; + } + } else { + colvar_centers.clear(); + cvm::error("Error: must define the initial centers of the restraints.\n"); + } + + if (colvar_centers.size() != colvars.size()) { + cvm::error("Error: number of centers does not match " + "that of collective variables.\n"); } - } else { - colvar_centers.clear(); - cvm::error ("Error: must define the initial centers of the restraints.\n"); } - if (colvar_centers.size() != colvars.size()) - cvm::error ("Error: number of centers does not match " - "that of collective variables.\n"); + { + if (cvm::debug()) { + cvm::log("colvarbias_restraint: parsing target centers.\n"); + } - if (get_keyval (conf, "targetCenters", target_centers, colvar_centers)) { - b_chg_centers = true; - for (size_t i = 0; i < target_centers.size(); i++) { - target_centers[i].apply_constraints(); + size_t i; + if (get_keyval(conf, "targetCenters", target_centers, colvar_centers)) { + b_chg_centers = true; + for (i = 0; i < target_centers.size(); i++) { + target_centers[i].apply_constraints(); + } + } else { + b_chg_centers = false; + target_centers.clear(); } - } else { - b_chg_centers = false; - target_centers.clear(); } - if (get_keyval (conf, "targetForceConstant", target_force_k, 0.0)) { + if (get_keyval(conf, "targetForceConstant", target_force_k, 0.0)) { if (b_chg_centers) - cvm::error ("Error: cannot specify both targetCenters and targetForceConstant.\n"); + cvm::error("Error: cannot specify both targetCenters and targetForceConstant.\n"); starting_force_k = force_k; b_chg_force_k = true; - get_keyval (conf, "targetEquilSteps", target_equil_steps, 0); + get_keyval(conf, "targetEquilSteps", target_equil_steps, 0); - get_keyval (conf, "lambdaSchedule", lambda_schedule, lambda_schedule); + get_keyval(conf, "lambdaSchedule", lambda_schedule, lambda_schedule); if (lambda_schedule.size()) { // There is one more lambda-point than stages target_nstages = lambda_schedule.size() - 1; } } else { b_chg_force_k = false; } if (b_chg_centers || b_chg_force_k) { - get_keyval (conf, "targetNumSteps", target_nsteps, 0); + get_keyval(conf, "targetNumSteps", target_nsteps, 0); if (!target_nsteps) - cvm::error ("Error: targetNumSteps must be non-zero.\n"); + cvm::error("Error: targetNumSteps must be non-zero.\n"); - if (get_keyval (conf, "targetNumStages", target_nstages, target_nstages) && + if (get_keyval(conf, "targetNumStages", target_nstages, target_nstages) && lambda_schedule.size()) { - cvm::error ("Error: targetNumStages and lambdaSchedule are incompatible.\n"); + cvm::error("Error: targetNumStages and lambdaSchedule are incompatible.\n"); } if (target_nstages) { // This means that either numStages of lambdaSchedule has been provided stage = 0; restraint_FE = 0.0; } - if (get_keyval (conf, "targetForceExponent", force_k_exp, 1.0)) { + if (get_keyval(conf, "targetForceExponent", force_k_exp, 1.0)) { if (! b_chg_force_k) - cvm::log ("Warning: not changing force constant: targetForceExponent will be ignored\n"); + cvm::log("Warning: not changing force constant: targetForceExponent will be ignored\n"); if (force_k_exp < 1.0) - cvm::log ("Warning: for all practical purposes, targetForceExponent should be 1.0 or greater.\n"); + cvm::log("Warning: for all practical purposes, targetForceExponent should be 1.0 or greater.\n"); } } - get_keyval (conf, "outputCenters", b_output_centers, false); + get_keyval(conf, "outputCenters", b_output_centers, false); if (b_chg_centers) { - get_keyval (conf, "outputAccumulatedWork", b_output_acc_work, false); + get_keyval(conf, "outputAccumulatedWork", b_output_acc_work, false); } else { b_output_acc_work = false; } acc_work = 0.0; if (cvm::debug()) - cvm::log ("Done initializing a new restraint bias.\n"); + cvm::log("Done initializing a new restraint bias.\n"); } -colvarbias_restraint::~colvarbias_restraint () +colvarbias_restraint::~colvarbias_restraint() { if (cvm::n_rest_biases > 0) cvm::n_rest_biases -= 1; } -void colvarbias_restraint::change_configuration (std::string const &conf) +void colvarbias_restraint::change_configuration(std::string const &conf) { - get_keyval (conf, "forceConstant", force_k, force_k); - if (get_keyval (conf, "centers", colvar_centers, colvar_centers)) { + get_keyval(conf, "forceConstant", force_k, force_k); + if (get_keyval(conf, "centers", colvar_centers, colvar_centers)) { for (size_t i = 0; i < colvars.size(); i++) { + colvar_centers[i].type(colvars[i]->value()); colvar_centers[i].apply_constraints(); + colvar_centers_raw[i].type(colvars[i]->value()); colvar_centers_raw[i] = colvar_centers[i]; } } } -cvm::real colvarbias_restraint::energy_difference (std::string const &conf) +cvm::real colvarbias_restraint::energy_difference(std::string const &conf) { std::vector alt_colvar_centers; cvm::real alt_force_k; cvm::real alt_bias_energy = 0.0; - get_keyval (conf, "forceConstant", alt_force_k, force_k); + get_keyval(conf, "forceConstant", alt_force_k, force_k); - alt_colvar_centers.resize (colvars.size()); + alt_colvar_centers.resize(colvars.size()); size_t i; for (i = 0; i < colvars.size(); i++) { - alt_colvar_centers[i].type (colvars[i]->type()); + alt_colvar_centers[i].type(colvars[i]->value()); } - if (get_keyval (conf, "centers", alt_colvar_centers, colvar_centers)) { + if (get_keyval(conf, "centers", alt_colvar_centers, colvar_centers)) { for (i = 0; i < colvars.size(); i++) { + colvar_centers[i].type(colvars[i]->value()); colvar_centers[i].apply_constraints(); } } for (i = 0; i < colvars.size(); i++) { alt_bias_energy += restraint_potential(restraint_convert_k(alt_force_k, colvars[i]->width), colvars[i], alt_colvar_centers[i]); } return alt_bias_energy - bias_energy; } cvm::real colvarbias_restraint::update() { bias_energy = 0.0; if (cvm::debug()) - cvm::log ("Updating the restraint bias \""+this->name+"\".\n"); + cvm::log("Updating the restraint bias \""+this->name+"\".\n"); // Setup first stage of staged variable force constant calculation if (b_chg_force_k && target_nstages && cvm::step_absolute() == 0) { cvm::real lambda; if (lambda_schedule.size()) { lambda = lambda_schedule[0]; } else { lambda = 0.0; } force_k = starting_force_k + (target_force_k - starting_force_k) - * std::pow (lambda, force_k_exp); - cvm::log ("Restraint " + this->name + ", stage " + + * std::pow(lambda, force_k_exp); + cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage) + " : lambda = " + cvm::to_str(lambda)); - cvm::log ("Setting force constant to " + cvm::to_str (force_k)); + cvm::log("Setting force constant to " + cvm::to_str(force_k)); } if (b_chg_centers) { if (!centers_incr.size()) { // if this is the first calculation, calculate the advancement // at each simulation step (or stage, if applicable) // (take current stage into account: it can be non-zero // if we are restarting a staged calculation) - centers_incr.resize (colvars.size()); + centers_incr.resize(colvars.size()); for (size_t i = 0; i < colvars.size(); i++) { - centers_incr[i].type (colvars[i]->type()); + centers_incr[i].type(colvars[i]->value()); centers_incr[i] = (target_centers[i] - colvar_centers_raw[i]) / - cvm::real ( target_nstages ? (target_nstages - stage) : + cvm::real( target_nstages ? (target_nstages - stage) : (target_nsteps - cvm::step_absolute())); } if (cvm::debug()) { - cvm::log ("Center increment for the restraint bias \""+ - this->name+"\": "+cvm::to_str (centers_incr)+" at stage "+cvm::to_str (stage)+ ".\n"); + cvm::log("Center increment for the restraint bias \""+ + this->name+"\": "+cvm::to_str(centers_incr)+" at stage "+cvm::to_str(stage)+ ".\n"); } } if (target_nstages) { if ((cvm::step_relative() > 0) && (cvm::step_absolute() % target_nsteps) == 0 && stage < target_nstages) { for (size_t i = 0; i < colvars.size(); i++) { colvar_centers_raw[i] += centers_incr[i]; colvar_centers[i] = colvar_centers_raw[i]; colvars[i]->wrap(colvar_centers[i]); colvar_centers[i].apply_constraints(); } stage++; - cvm::log ("Moving restraint \"" + this->name + + cvm::log("Moving restraint \"" + this->name + "\" stage " + cvm::to_str(stage) + - " : setting centers to " + cvm::to_str (colvar_centers) + - " at step " + cvm::to_str (cvm::step_absolute())); + " : setting centers to " + cvm::to_str(colvar_centers) + + " at step " + cvm::to_str(cvm::step_absolute())); } } else if ((cvm::step_relative() > 0) && (cvm::step_absolute() <= target_nsteps)) { // move the restraint centers in the direction of the targets // (slow growth) for (size_t i = 0; i < colvars.size(); i++) { colvar_centers_raw[i] += centers_incr[i]; colvar_centers[i] = colvar_centers_raw[i]; colvars[i]->wrap(colvar_centers[i]); colvar_centers[i].apply_constraints(); } } if (cvm::debug()) - cvm::log ("Current centers for the restraint bias \""+ - this->name+"\": "+cvm::to_str (colvar_centers)+".\n"); + cvm::log("Current centers for the restraint bias \""+ + this->name+"\": "+cvm::to_str(colvar_centers)+".\n"); } if (b_chg_force_k) { // Coupling parameter, between 0 and 1 cvm::real lambda; if (target_nstages) { // TI calculation: estimate free energy derivative // need current lambda if (lambda_schedule.size()) { lambda = lambda_schedule[stage]; } else { lambda = cvm::real(stage) / cvm::real(target_nstages); } if (target_equil_steps == 0 || cvm::step_absolute() % target_nsteps >= target_equil_steps) { // Start averaging after equilibration period, if requested // Square distance normalized by square colvar width cvm::real dist_sq = 0.0; for (size_t i = 0; i < colvars.size(); i++) { - dist_sq += colvars[i]->dist2 (colvars[i]->value(), colvar_centers[i]) + dist_sq += colvars[i]->dist2(colvars[i]->value(), colvar_centers[i]) / (colvars[i]->width * colvars[i]->width); } restraint_FE += 0.5 * force_k_exp * std::pow(lambda, force_k_exp - 1.0) * (target_force_k - starting_force_k) * dist_sq; } // Finish current stage... if (cvm::step_absolute() % target_nsteps == 0 && cvm::step_absolute() > 0) { - cvm::log ("Lambda= " + cvm::to_str (lambda) + " dA/dLambda= " - + cvm::to_str (restraint_FE / cvm::real(target_nsteps - target_equil_steps))); + cvm::log("Lambda= " + cvm::to_str(lambda) + " dA/dLambda= " + + cvm::to_str(restraint_FE / cvm::real(target_nsteps - target_equil_steps))); // ...and move on to the next one if (stage < target_nstages) { restraint_FE = 0.0; stage++; if (lambda_schedule.size()) { lambda = lambda_schedule[stage]; } else { lambda = cvm::real(stage) / cvm::real(target_nstages); } force_k = starting_force_k + (target_force_k - starting_force_k) - * std::pow (lambda, force_k_exp); - cvm::log ("Restraint " + this->name + ", stage " + + * std::pow(lambda, force_k_exp); + cvm::log("Restraint " + this->name + ", stage " + cvm::to_str(stage) + " : lambda = " + cvm::to_str(lambda)); - cvm::log ("Setting force constant to " + cvm::to_str (force_k)); + cvm::log("Setting force constant to " + cvm::to_str(force_k)); } } } else if (cvm::step_absolute() <= target_nsteps) { // update force constant (slow growth) lambda = cvm::real(cvm::step_absolute()) / cvm::real(target_nsteps); force_k = starting_force_k + (target_force_k - starting_force_k) - * std::pow (lambda, force_k_exp); + * std::pow(lambda, force_k_exp); } } if (cvm::debug()) - cvm::log ("Done updating the restraint bias \""+this->name+"\".\n"); + cvm::log("Done updating the restraint bias \""+this->name+"\".\n"); // Force and energy calculation for (size_t i = 0; i < colvars.size(); i++) { + colvar_forces[i].type(colvars[i]->value()); colvar_forces[i] = -1.0 * restraint_force(restraint_convert_k(force_k, colvars[i]->width), colvars[i], colvar_centers[i]); bias_energy += restraint_potential(restraint_convert_k(force_k, colvars[i]->width), colvars[i], colvar_centers[i]); if (cvm::debug()) { - cvm::log ("dist_grad["+cvm::to_str (i)+ - "] = "+cvm::to_str (colvars[i]->dist2_lgrad (colvars[i]->value(), + cvm::log("dist_grad["+cvm::to_str(i)+ + "] = "+cvm::to_str(colvars[i]->dist2_lgrad(colvars[i]->value(), colvar_centers[i]))+"\n"); } } if (b_output_acc_work) { if ((cvm::step_relative() > 0) || (cvm::step_absolute() == 0)) { for (size_t i = 0; i < colvars.size(); i++) { // project forces on the calculated increments at this step acc_work += colvar_forces[i] * centers_incr[i]; } } } if (cvm::debug()) - cvm::log ("Current forces for the restraint bias \""+ - this->name+"\": "+cvm::to_str (colvar_forces)+".\n"); + cvm::log("Current forces for the restraint bias \""+ + this->name+"\": "+cvm::to_str(colvar_forces)+".\n"); return bias_energy; } -std::istream & colvarbias_restraint::read_restart (std::istream &is) +std::istream & colvarbias_restraint::read_restart(std::istream &is) { size_t const start_pos = is.tellg(); - cvm::log ("Restarting restraint bias \""+ + cvm::log("Restarting restraint bias \""+ this->name+"\".\n"); std::string key, brace, conf; if ( !(is >> key) || !(key == "restraint" || key == "harmonic") || !(is >> brace) || !(brace == "{") || - !(is >> colvarparse::read_block ("configuration", conf)) ) { + !(is >> colvarparse::read_block("configuration", conf)) ) { - cvm::log ("Error: in reading restart configuration for restraint bias \""+ + cvm::log("Error: in reading restart configuration for restraint bias \""+ this->name+"\" at position "+ - cvm::to_str (is.tellg())+" in stream.\n"); + cvm::to_str(is.tellg())+" in stream.\n"); is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } // int id = -1; std::string name = ""; // if ( ( (colvarparse::get_keyval (conf, "id", id, -1, colvarparse::parse_silent)) && // (id != this->id) ) || - if ( (colvarparse::get_keyval (conf, "name", name, std::string (""), colvarparse::parse_silent)) && + if ( (colvarparse::get_keyval(conf, "name", name, std::string(""), colvarparse::parse_silent)) && (name != this->name) ) - cvm::error ("Error: in the restart file, the " + cvm::error("Error: in the restart file, the " "\"restraint\" block has a wrong name\n"); // if ( (id == -1) && (name == "") ) { if (name.size() == 0) { - cvm::error ("Error: \"restraint\" block in the restart file " + cvm::error("Error: \"restraint\" block in the restart file " "has no identifiers.\n"); } if (b_chg_centers) { // cvm::log ("Reading the updated restraint centers from the restart.\n"); - if (!get_keyval (conf, "centers", colvar_centers)) - cvm::error ("Error: restraint centers are missing from the restart.\n"); - if (!get_keyval (conf, "centers_raw", colvar_centers_raw)) - cvm::error ("Error: \"raw\" restraint centers are missing from the restart.\n"); + if (!get_keyval(conf, "centers", colvar_centers)) + cvm::error("Error: restraint centers are missing from the restart.\n"); + if (!get_keyval(conf, "centers_raw", colvar_centers_raw)) + cvm::error("Error: \"raw\" restraint centers are missing from the restart.\n"); } if (b_chg_force_k) { // cvm::log ("Reading the updated force constant from the restart.\n"); - if (!get_keyval (conf, "forceConstant", force_k)) - cvm::error ("Error: force constant is missing from the restart.\n"); + if (!get_keyval(conf, "forceConstant", force_k)) + cvm::error("Error: force constant is missing from the restart.\n"); } if (target_nstages) { // cvm::log ("Reading current stage from the restart.\n"); - if (!get_keyval (conf, "stage", stage)) - cvm::error ("Error: current stage is missing from the restart.\n"); + if (!get_keyval(conf, "stage", stage)) + cvm::error("Error: current stage is missing from the restart.\n"); } if (b_output_acc_work) { - if (!get_keyval (conf, "accumulatedWork", acc_work)) - cvm::error ("Error: accumulatedWork is missing from the restart.\n"); + if (!get_keyval(conf, "accumulatedWork", acc_work)) + cvm::error("Error: accumulatedWork is missing from the restart.\n"); } is >> brace; if (brace != "}") { - cvm::error ("Error: corrupt restart information for restraint bias \""+ + cvm::error("Error: corrupt restart information for restraint bias \""+ this->name+"\": no matching brace at position "+ - cvm::to_str (is.tellg())+" in the restart file.\n"); - is.setstate (std::ios::failbit); + cvm::to_str(is.tellg())+" in the restart file.\n"); + is.setstate(std::ios::failbit); } return is; } -std::ostream & colvarbias_restraint::write_restart (std::ostream &os) +std::ostream & colvarbias_restraint::write_restart(std::ostream &os) { os << "restraint {\n" << " configuration {\n" // << " id " << this->id << "\n" << " name " << this->name << "\n"; if (b_chg_centers) { size_t i; os << " centers "; for (i = 0; i < colvars.size(); i++) { os << " " << colvar_centers[i]; } os << "\n"; os << " centers_raw "; for (i = 0; i < colvars.size(); i++) { os << " " << colvar_centers_raw[i]; } os << "\n"; } if (b_chg_force_k) { os << " forceConstant " - << std::setprecision (cvm::en_prec) - << std::setw (cvm::en_width) << force_k << "\n"; + << std::setprecision(cvm::en_prec) + << std::setw(cvm::en_width) << force_k << "\n"; } if (target_nstages) { - os << " stage " << std::setw (cvm::it_width) + os << " stage " << std::setw(cvm::it_width) << stage << "\n"; } if (b_output_acc_work) { os << " accumulatedWork " << acc_work << "\n"; } os << " }\n" << "}\n\n"; return os; } -std::ostream & colvarbias_restraint::write_traj_label (std::ostream &os) +std::ostream & colvarbias_restraint::write_traj_label(std::ostream &os) { os << " "; if (b_output_energy) os << " E_" - << cvm::wrap_string (this->name, cvm::en_width-2); + << cvm::wrap_string(this->name, cvm::en_width-2); if (b_output_centers) for (size_t i = 0; i < colvars.size(); i++) { - size_t const this_cv_width = (colvars[i]->value()).output_width (cvm::cv_width); + size_t const this_cv_width = (colvars[i]->value()).output_width(cvm::cv_width); os << " x0_" - << cvm::wrap_string (colvars[i]->name, this_cv_width-3); + << cvm::wrap_string(colvars[i]->name, this_cv_width-3); } if (b_output_acc_work) os << " W_" - << cvm::wrap_string (this->name, cvm::en_width-2); + << cvm::wrap_string(this->name, cvm::en_width-2); return os; } -std::ostream & colvarbias_restraint::write_traj (std::ostream &os) +std::ostream & colvarbias_restraint::write_traj(std::ostream &os) { os << " "; if (b_output_energy) os << " " - << std::setprecision (cvm::en_prec) << std::setw (cvm::en_width) + << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width) << bias_energy; if (b_output_centers) for (size_t i = 0; i < colvars.size(); i++) { os << " " - << std::setprecision (cvm::cv_prec) << std::setw (cvm::cv_width) + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) << colvar_centers[i]; } if (b_output_acc_work) os << " " - << std::setprecision (cvm::en_prec) << std::setw (cvm::en_width) + << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width) << acc_work; return os; } colvarbias_restraint_harmonic::colvarbias_restraint_harmonic(std::string const &conf, char const *key) : colvarbias_restraint(conf, key) { for (size_t i = 0; i < colvars.size(); i++) { if (colvars[i]->width != 1.0) - cvm::log ("The force constant for colvar \""+colvars[i]->name+ + cvm::log("The force constant for colvar \""+colvars[i]->name+ "\" will be rescaled to "+ - cvm::to_str (restraint_convert_k(force_k, colvars[i]->width))+ + cvm::to_str(restraint_convert_k(force_k, colvars[i]->width))+ " according to the specified width.\n"); } } cvm::real colvarbias_restraint_harmonic::restraint_potential(cvm::real k, colvar* x, const colvarvalue &xcenter) const { return 0.5 * k * x->dist2(x->value(), xcenter); } colvarvalue colvarbias_restraint_harmonic::restraint_force(cvm::real k, colvar* x, const colvarvalue &xcenter) const { return 0.5 * k * x->dist2_lgrad(x->value(), xcenter); } cvm::real colvarbias_restraint_harmonic::restraint_convert_k(cvm::real k, cvm::real dist_measure) const { return k / (dist_measure * dist_measure); } colvarbias_restraint_linear::colvarbias_restraint_linear(std::string const &conf, char const *key) : colvarbias_restraint(conf, key) { for (size_t i = 0; i < colvars.size(); i++) { if (colvars[i]->width != 1.0) - cvm::log ("The force constant for colvar \""+colvars[i]->name+ + cvm::log("The force constant for colvar \""+colvars[i]->name+ "\" will be rescaled to "+ - cvm::to_str (restraint_convert_k(force_k, colvars[i]->width))+ + cvm::to_str(restraint_convert_k(force_k, colvars[i]->width))+ " according to the specified width.\n"); } } cvm::real colvarbias_restraint_linear::restraint_potential(cvm::real k, colvar* x, const colvarvalue &xcenter) const { return k * (x->value() - xcenter); } colvarvalue colvarbias_restraint_linear::restraint_force(cvm::real k, colvar* x, const colvarvalue &xcenter) const { return k; } cvm::real colvarbias_restraint_linear::restraint_convert_k(cvm::real k, cvm::real dist_measure) const { return k / dist_measure; } diff --git a/lib/colvars/colvarbias_restraint.h b/lib/colvars/colvarbias_restraint.h index 1e55c6e07..91f37181d 100644 --- a/lib/colvars/colvarbias_restraint.h +++ b/lib/colvars/colvarbias_restraint.h @@ -1,153 +1,153 @@ /// -*- c++ -*- #ifndef COLVARBIAS_RESTRAINT_H #define COLVARBIAS_RESTRAINT_H #include "colvarbias.h" /// \brief Bias restraint, optionally moving towards a target /// (implementation of \link colvarbias \endlink) class colvarbias_restraint : public colvarbias { public: /// Retrieve colvar values and calculate their biasing forces virtual cvm::real update(); /// Load new configuration - force constant and/or centers only virtual void change_configuration(std::string const &conf); /// Calculate change in energy from using alternate configuration virtual cvm::real energy_difference(std::string const &conf); /// Read the bias configuration from a restart file - virtual std::istream & read_restart (std::istream &is); + virtual std::istream & read_restart(std::istream &is); /// Write the bias configuration to a restart file - virtual std::ostream & write_restart (std::ostream &os); + virtual std::ostream & write_restart(std::ostream &os); /// Write a label to the trajectory file (comment line) - virtual std::ostream & write_traj_label (std::ostream &os); + virtual std::ostream & write_traj_label(std::ostream &os); /// Output quantities such as the bias energy to the trajectory file - virtual std::ostream & write_traj (std::ostream &os); + virtual std::ostream & write_traj(std::ostream &os); /// \brief Constructor - colvarbias_restraint (std::string const &conf, char const *key); + colvarbias_restraint(std::string const &conf, char const *key); /// Destructor virtual ~colvarbias_restraint(); protected: /// \brief Potential function virtual cvm::real restraint_potential(cvm::real k, colvar* x, const colvarvalue& xcenter) const = 0; /// \brief Force function virtual colvarvalue restraint_force(cvm::real k, colvar* x, const colvarvalue& xcenter) const = 0; ///\brief Unit scaling virtual cvm::real restraint_convert_k(cvm::real k, cvm::real dist_measure) const = 0; /// \brief Restraint centers std::vector colvar_centers; /// \brief Restraint centers without wrapping or constraints applied std::vector colvar_centers_raw; /// \brief Moving target? bool b_chg_centers; /// \brief New restraint centers std::vector target_centers; /// \brief Amplitude of the restraint centers' increment at each step /// (or stage) towards the new values (calculated from target_nsteps) std::vector centers_incr; /// Whether to write the current restraint centers to the trajectory file bool b_output_centers; /// Whether to write the current accumulated work to the trajectory file bool b_output_acc_work; /// \brief Accumulated work cvm::real acc_work; /// \brief Restraint force constant cvm::real force_k; /// \brief Changing force constant? bool b_chg_force_k; /// \brief Restraint force constant (target value) cvm::real target_force_k; /// \brief Restraint force constant (starting value) cvm::real starting_force_k; /// \brief Lambda-schedule for custom varying force constant std::vector lambda_schedule; /// \brief Exponent for varying the force constant cvm::real force_k_exp; /// \brief Intermediate quantity to compute the restraint free energy /// (in TI, would be the accumulating FE derivative) cvm::real restraint_FE; /// \brief Equilibration steps for restraint FE calculation through TI cvm::real target_equil_steps; /// \brief Number of stages over which to perform the change /// If zero, perform a continuous change int target_nstages; /// \brief Number of current stage of the perturbation int stage; /// \brief Number of steps required to reach the target force constant /// or restraint centers size_t target_nsteps; }; /// \brief Harmonic bias restraint /// (implementation of \link colvarbias_restraint \endlink) class colvarbias_restraint_harmonic : public colvarbias_restraint { public: colvarbias_restraint_harmonic(std::string const &conf, char const *key); protected: /// \brief Potential function virtual cvm::real restraint_potential(cvm::real k, colvar* x, const colvarvalue& xcenter) const; /// \brief Force function virtual colvarvalue restraint_force(cvm::real k, colvar* x, const colvarvalue& xcenter) const; ///\brief Unit scaling virtual cvm::real restraint_convert_k(cvm::real k, cvm::real dist_measure) const; }; /// \brief Linear bias restraint /// (implementation of \link colvarbias_restraint \endlink) class colvarbias_restraint_linear : public colvarbias_restraint { public: colvarbias_restraint_linear(std::string const &conf, char const *key); protected: /// \brief Potential function virtual cvm::real restraint_potential(cvm::real k, colvar* x, const colvarvalue& xcenter) const; /// \brief Force function virtual colvarvalue restraint_force(cvm::real k, colvar* x, const colvarvalue& xcenter) const; ///\brief Unit scaling virtual cvm::real restraint_convert_k(cvm::real k, cvm::real dist_measure) const; }; #endif diff --git a/lib/colvars/colvarcomp.cpp b/lib/colvars/colvarcomp.cpp index 949256004..fc31c44ab 100644 --- a/lib/colvars/colvarcomp.cpp +++ b/lib/colvars/colvarcomp.cpp @@ -1,187 +1,189 @@ /// -*- c++ -*- #include "colvarmodule.h" #include "colvarvalue.h" #include "colvar.h" #include "colvarcomp.h" colvar::cvc::cvc() - : sup_coeff (1.0), sup_np (1), - b_periodic (false), - b_inverse_gradients (false), - b_Jacobian_derivative (false), - b_debug_gradients (false) + : sup_coeff(1.0), sup_np(1), + b_periodic(false), + b_inverse_gradients(false), + b_Jacobian_derivative(false), + b_debug_gradients(false) {} -colvar::cvc::cvc (std::string const &conf) - : sup_coeff (1.0), sup_np (1), - b_periodic (false), - b_inverse_gradients (false), - b_Jacobian_derivative (false), - b_debug_gradients (false) +colvar::cvc::cvc(std::string const &conf) + : sup_coeff(1.0), sup_np(1), + b_periodic(false), + b_inverse_gradients(false), + b_Jacobian_derivative(false), + b_debug_gradients(false) { if (cvm::debug()) - cvm::log ("Initializing cvc base object.\n"); + cvm::log("Initializing cvc base object.\n"); - get_keyval (conf, "name", this->name, std::string (""), parse_silent); + get_keyval(conf, "name", this->name, std::string(""), parse_silent); - get_keyval (conf, "componentCoeff", sup_coeff, 1.0); - get_keyval (conf, "componentExp", sup_np, 1); + get_keyval(conf, "componentCoeff", sup_coeff, 1.0); + get_keyval(conf, "componentExp", sup_np, 1); - get_keyval (conf, "period", period, 0.0); - get_keyval (conf, "wrapAround", wrap_center, 0.0); + get_keyval(conf, "period", period, 0.0); + get_keyval(conf, "wrapAround", wrap_center, 0.0); - get_keyval (conf, "debugGradients", b_debug_gradients, false, parse_silent); + get_keyval(conf, "debugGradients", b_debug_gradients, false, parse_silent); if (cvm::debug()) - cvm::log ("Done initializing cvc base object.\n"); + cvm::log("Done initializing cvc base object.\n"); } -void colvar::cvc::parse_group (std::string const &conf, +void colvar::cvc::parse_group(std::string const &conf, char const *group_key, cvm::atom_group &group, bool optional) { - if (key_lookup (conf, group_key)) { - if (group.parse (conf, group_key) != COLVARS_OK) { - cvm::error ("Error parsing definition for atom group \""+ - std::string (group_key)+"\".\n"); + if (key_lookup(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::error ("Error: definition for atom group \""+ - std::string (group_key)+"\" not found.\n"); + cvm::error("Error: definition for atom group \""+ + std::string(group_key)+"\" not found.\n"); return; } } } colvar::cvc::~cvc() {} void colvar::cvc::calc_force_invgrads() { - cvm::fatal_error ("Error: calculation of inverse gradients is not implemented " + cvm::fatal_error("Error: calculation of inverse gradients is not implemented " "for colvar components of type \""+function_type+"\".\n"); } void colvar::cvc::calc_Jacobian_derivative() { - cvm::fatal_error ("Error: calculation of inverse gradients is not implemented " + cvm::fatal_error("Error: calculation of inverse gradients is not implemented " "for colvar components of type \""+function_type+"\".\n"); } -void colvar::cvc::debug_gradients (cvm::atom_group &group) +void colvar::cvc::debug_gradients(cvm::atom_group &group) { // this function should work for any scalar variable: // the only difference will be the name of the atom group (here, "group") if (group.b_dummy) return; cvm::rotation const rot_0 = group.rot; cvm::rotation const rot_inv = group.rot.inverse(); - cvm::real const x_0 = x.real_value; + cvm::real x_0 = x.real_value; + if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0]; - // cvm::log ("gradients = "+cvm::to_str (gradients)+"\n"); + // cvm::log("gradients = "+cvm::to_str (gradients)+"\n"); // it only makes sense to debug the fit gradients // when the fitting group is the same as this group if (group.b_rotate || group.b_center) if (group.b_fit_gradients && (group.ref_pos_group == NULL)) { group.calc_fit_gradients(); if (group.b_rotate) { // fit_gradients are in the original frame, we should print them in the rotated frame for (size_t j = 0; j < group.fit_gradients.size(); j++) { - group.fit_gradients[j] = rot_0.rotate (group.fit_gradients[j]); + group.fit_gradients[j] = rot_0.rotate(group.fit_gradients[j]); } } - cvm::log ("fit_gradients = "+cvm::to_str (group.fit_gradients)+"\n"); + cvm::log("fit_gradients = "+cvm::to_str(group.fit_gradients)+"\n"); if (group.b_rotate) { for (size_t j = 0; j < group.fit_gradients.size(); j++) { - group.fit_gradients[j] = rot_inv.rotate (group.fit_gradients[j]); + group.fit_gradients[j] = rot_inv.rotate(group.fit_gradients[j]); } } } for (size_t ia = 0; ia < group.size(); ia++) { // tests are best conducted in the unrotated (simulation) frame cvm::rvector const atom_grad = group.b_rotate ? - rot_inv.rotate (group[ia].grad) : + rot_inv.rotate(group[ia].grad) : group[ia].grad; for (size_t id = 0; id < 3; id++) { // (re)read original positions group.read_positions(); // change one coordinate group[ia].pos[id] += cvm::debug_gradients_step_size; // (re)do the fit (if defined) if (group.b_center || group.b_rotate) { group.calc_apply_roto_translation(); } calc_value(); - cvm::real const x_1 = x.real_value; - cvm::log ("Atom "+cvm::to_str (ia)+", component "+cvm::to_str (id)+":\n"); - cvm::log ("dx(actual) = "+cvm::to_str (x_1 - x_0, + cvm::real x_1 = x.real_value; + if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_1 = x[0]; + cvm::log("Atom "+cvm::to_str(ia)+", component "+cvm::to_str(id)+":\n"); + cvm::log("dx(actual) = "+cvm::to_str(x_1 - x_0, 21, 14)+"\n"); //cvm::real const dx_pred = (group.fit_gradients.size() && (group.ref_pos_group == NULL)) ? cvm::real const dx_pred = (group.fit_gradients.size()) ? (cvm::debug_gradients_step_size * (atom_grad[id] + group.fit_gradients[ia][id])) : (cvm::debug_gradients_step_size * atom_grad[id]); - cvm::log ("dx(interp) = "+cvm::to_str (dx_pred, + cvm::log("dx(interp) = "+cvm::to_str(dx_pred, 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"); + 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"); } } /* * The code below is WIP */ // if (group.ref_pos_group != NULL) { // cvm::atom_group &ref = *group.ref_pos_group; // group.calc_fit_gradients(); // // for (size_t ia = 0; ia < ref.size(); ia++) { // // for (size_t id = 0; id < 3; id++) { // // (re)read original positions // group.read_positions(); // ref.read_positions(); // // change one coordinate // ref[ia].pos[id] += cvm::debug_gradients_step_size; // group.calc_apply_roto_translation(); // calc_value(); // cvm::real const x_1 = x.real_value; -// cvm::log ("refPosGroup atom "+cvm::to_str (ia)+", component "+cvm::to_str (id)+":\n"); -// cvm::log ("dx(actual) = "+cvm::to_str (x_1 - x_0, +// cvm::log("refPosGroup atom "+cvm::to_str(ia)+", component "+cvm::to_str (id)+":\n"); +// cvm::log("dx(actual) = "+cvm::to_str (x_1 - x_0, // 21, 14)+"\n"); // //cvm::real const dx_pred = (group.fit_gradients.size() && (group.ref_pos_group == NULL)) ? // // cvm::real const dx_pred = (group.fit_gradients.size()) ? // // (cvm::debug_gradients_step_size * (atom_grad[id] + group.fit_gradients[ia][id])) : // // (cvm::debug_gradients_step_size * atom_grad[id]); // cvm::real const dx_pred = cvm::debug_gradients_step_size * ref.fit_gradients[ia][id]; -// cvm::log ("dx(interp) = "+cvm::to_str (dx_pred, +// cvm::log("dx(interp) = "+cvm::to_str (dx_pred, // 21, 14)+"\n"); // cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+ -// cvm::to_str (std::fabs (x_1 - x_0 - dx_pred) / +// cvm::to_str(std::fabs (x_1 - x_0 - dx_pred) / // std::fabs (x_1 - x_0), // 12, 5)+ // ".\n"); // } // } // } return; } diff --git a/lib/colvars/colvarcomp.h b/lib/colvars/colvarcomp.h index 735c2f5bc..69348da36 100644 --- a/lib/colvars/colvarcomp.h +++ b/lib/colvars/colvarcomp.h @@ -1,1359 +1,1414 @@ /// -*- c++ -*- #ifndef COLVARCOMP_H #define COLVARCOMP_H // Declaration of colvar::cvc base class and derived ones. // // Future cvc's could be declared on additional header files. // After the declaration of a new derived class, its metric // functions must be reimplemented as well. // If the new cvc has no symmetry or periodicity, // this can be done straightforwardly by using the macro: // simple_scalar_dist_functions (derived_class) #include #include #include "colvarmodule.h" #include "colvar.h" #include "colvaratoms.h" /// \brief Colvar component (base class); most implementations of /// \link cvc \endlink utilize one or more \link /// colvarmodule::atom \endlink or \link colvarmodule::atom_group /// \endlink objects to access atoms. /// /// A \link cvc \endlink object (or an object of a /// cvc-derived class) specifies how to calculate a collective /// variable, its gradients and other related physical quantities /// which do not depend only on the numeric value (the \link colvar /// \endlink class already serves this purpose). /// /// No restriction is set to what kind of calculation a \link /// cvc \endlink object performs (usually calculate an /// analytical function of atomic coordinates). The only constraint /// is that the value calculated is implemented as a \link colvarvalue /// \endlink object. This serves to provide a unique way to calculate /// scalar and non-scalar collective variables, and specify if and how /// they can be combined together by the parent \link colvar \endlink /// object. /// /// If you wish to implement a new collective variable component, you /// should write your own class by inheriting directly from \link /// cvc \endlink, or one of its derived classes (for instance, /// \link distance \endlink is frequently used, because it provides /// useful data and function members for any colvar based on two /// atom groups). The steps are: \par /// 1. add the name of this class under colvar.h \par /// 2. add a call to the parser in colvar.C, within the function colvar::colvar() \par /// 3. declare the class in colvarcomp.h \par /// 4. implement the class in one of the files colvarcomp_*.C /// /// /// The cvm::atom and cvm::atom_group classes are available to /// transparently communicate with the simulation program. However, /// they are not strictly needed, as long as all the degrees of /// freedom associated to the cvc are properly evolved by a simple /// call to e.g. apply_force(). class colvar::cvc : public colvarparse { public: /// \brief The name of the object (helps to identify this /// cvc instance when debugging) std::string name; /// \brief Description of the type of collective variable /// /// Normally this string is set by the parent \link colvar \endlink /// object within its constructor, when all \link cvc \endlink /// objects are initialized; therefore the main "config string" /// constructor does not need to define it. If a \link cvc /// \endlink is initialized and/or a different constructor is used, /// this variable definition should be set within the constructor. std::string function_type; - /// \brief Type of \link colvarvalue \endlink that this cvc - /// provides - colvarvalue::Type type() const; - /// \brief Coefficient in the polynomial combination (default: 1.0) cvm::real sup_coeff; /// \brief Exponent in the polynomial combination (default: 1) int sup_np; /// \brief Period of this cvc value, (default: 0.0, non periodic) cvm::real period; /// \brief If the component is periodic, wrap around this value (default: 0.0) cvm::real wrap_center; bool b_periodic; /// \brief Constructor /// /// At least one constructor which reads a string should be defined /// for every class inheriting from cvc \param conf Contents /// of the configuration file pertaining to this \link cvc /// \endlink - cvc (std::string const &conf); + cvc(std::string const &conf); /// \brief Within the constructor, make a group parse its own /// options from the provided configuration string - void parse_group (std::string const &conf, - char const *group_key, - cvm::atom_group &group, - bool optional = false); + void parse_group(std::string const &conf, + char const *group_key, + cvm::atom_group &group, + bool optional = false); /// \brief Default constructor (used when \link cvc \endlink /// objects are declared within other ones) cvc(); /// Destructor virtual ~cvc(); /// \brief If this flag is false (default), inverse gradients /// (derivatives of atom coordinates with respect to x) are /// unavailable; it should be set to true by the constructor of each /// derived object capable of calculating them bool b_inverse_gradients; /// \brief If this flag is false (default), the Jacobian derivative /// (divergence of the inverse gradients) is unavailable; it should /// be set to true by the constructor of each derived object capable /// of calculating it bool b_Jacobian_derivative; /// \brief Calculate the variable virtual void calc_value() = 0; /// \brief Calculate the atomic gradients, to be reused later in /// order to apply forces virtual void calc_gradients() = 0; /// \brief If true, calc_gradients() will call debug_gradients() for every group needed bool b_debug_gradients; /// \brief Calculate finite-difference gradients alongside the analytical ones, for each Cartesian component - virtual void debug_gradients (cvm::atom_group &group); + virtual void debug_gradients(cvm::atom_group &group); /// \brief Calculate the total force from the system using the /// inverse atomic gradients virtual void calc_force_invgrads(); /// \brief Calculate the divergence of the inverse atomic gradients virtual void calc_Jacobian_derivative(); /// \brief Return the previously calculated value - virtual colvarvalue value() const; + virtual colvarvalue const & value() const; - /// \brief Return const pointer to the previously calculated value - virtual const colvarvalue *p_value() const; + // /// \brief Return const pointer to the previously calculated value + // virtual const colvarvalue *p_value() const; /// \brief Return the previously calculated system force - virtual colvarvalue system_force() const; + virtual colvarvalue const & system_force() const; /// \brief Return the previously calculated divergence of the /// inverse atomic gradients - virtual colvarvalue Jacobian_derivative() const; + virtual colvarvalue const & Jacobian_derivative() const; /// \brief Apply the collective variable force, by communicating the /// atomic forces to the simulation program (\b Note: the \link ft /// \endlink member is not altered by this function) /// /// Note: multiple calls to this function within the same simulation /// step will add the forces altogether \param cvforce The /// collective variable force, usually coming from the biases and /// eventually manipulated by the parent \link colvar \endlink /// object - virtual void apply_force (colvarvalue const &cvforce) = 0; + virtual void apply_force(colvarvalue const &cvforce) = 0; /// \brief Square distance between x1 and x2 (can be redefined to /// transparently implement constraints, symmetries and /// periodicities) /// /// colvar::cvc::dist2() and the related functions are /// declared as "const" functions, but not "static", because /// additional parameters defining the metrics (e.g. the /// periodicity) may be specific to each colvar::cvc object. /// /// If symmetries or periodicities are present, the /// colvar::cvc::dist2() should be redefined to return the /// "closest distance" value and colvar::cvc::dist2_lgrad(), /// colvar::cvc::dist2_rgrad() to return its gradients. /// /// If constraints are present (and not already implemented by any /// of the \link colvarvalue \endlink types), the /// colvar::cvc::dist2_lgrad() and /// colvar::cvc::dist2_rgrad() functions should be redefined /// to provide a gradient which is compatible with the constraint, /// i.e. already deprived of its component normal to the constraint /// hypersurface. /// /// Finally, another useful application, if you are performing very /// many operations with these functions, could be to override the /// \link colvarvalue \endlink member functions and access directly /// its member data. For instance: to define dist2(x1,x2) as /// (x2.real_value-x1.real_value)*(x2.real_value-x1.real_value) in /// case of a scalar \link colvarvalue \endlink type. - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; - /// \brief Gradient (with respect to x1) of the square distance (can + /// \brief Gradient(with respect to x1) of the square distance (can /// be redefined to transparently implement constraints, symmetries /// and periodicities) - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; - /// \brief Gradient (with respect to x2) of the square distance (can + /// \brief Gradient(with respect to x2) of the square distance (can /// be redefined to transparently implement constraints, symmetries /// and periodicities) - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; /// \brief Wrapp value (for periodic/symmetric cvcs) - virtual void wrap (colvarvalue &x) const; + virtual void wrap(colvarvalue &x) const; /// \brief Pointers to all atom groups, to let colvars collect info /// e.g. atomic gradients std::vector atom_groups; protected: /// \brief Cached value colvarvalue x; /// \brief Value at the previous step colvarvalue x_old; /// \brief Calculated system force (\b Note: this is calculated from /// the total atomic forces read from the program, subtracting fromt /// the "internal" forces of the system the "external" forces from /// the colvar biases) colvarvalue ft; /// \brief Calculated Jacobian derivative (divergence of the inverse /// gradients): serves to calculate the phase space correction colvarvalue jd; }; -inline colvarvalue::Type colvar::cvc::type() const -{ - return x.type(); -} - -inline colvarvalue colvar::cvc::value() const +inline colvarvalue const & colvar::cvc::value() const { return x; } -inline const colvarvalue * colvar::cvc::p_value() const -{ - return &x; -} +// inline const colvarvalue * colvar::cvc::p_value() const +// { +// return &x; +// } -inline colvarvalue colvar::cvc::system_force() const +inline colvarvalue const & colvar::cvc::system_force() const { return ft; } -inline colvarvalue colvar::cvc::Jacobian_derivative() const +inline colvarvalue const & colvar::cvc::Jacobian_derivative() const { return jd; } -inline cvm::real colvar::cvc::dist2 (colvarvalue const &x1, - colvarvalue const &x2) const +inline cvm::real colvar::cvc::dist2(colvarvalue const &x1, + colvarvalue const &x2) const { - return x1.dist2 (x2); + return x1.dist2(x2); } -inline colvarvalue colvar::cvc::dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::cvc::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - return x1.dist2_grad (x2); + return x1.dist2_grad(x2); } -inline colvarvalue colvar::cvc::dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::cvc::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - return x2.dist2_grad (x1); + return x2.dist2_grad(x1); } -inline void colvar::cvc::wrap (colvarvalue &x) const +inline void colvar::cvc::wrap(colvarvalue &x) const { return; } /// \brief Colvar component: distance between the centers of mass of /// two groups (colvarvalue::type_scalar type, range [0:*)) /// /// This class also serves as the template for many collective /// variables with two atom groups: in this case, the /// distance::distance() constructor should be called on the same /// configuration string, to make the same member data and functions /// available to the derived object class colvar::distance : public colvar::cvc { protected: /// First atom group cvm::atom_group group1; /// Second atom group cvm::atom_group group2; /// Vector distance, cached to be recycled cvm::rvector dist_v; /// Use absolute positions, ignoring PBCs when present bool b_no_PBC; /// Compute system force on first site only to avoid unwanted /// coupling to other colvars (see e.g. Ciccotti et al., 2005) bool b_1site_force; public: - distance (std::string const &conf, bool twogroups = true); + distance(std::string const &conf, bool twogroups = true); distance(); virtual inline ~distance() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; // \brief Colvar component: distance vector between centers of mass -// of two groups (\link colvarvalue::type_vector \endlink type, +// of two groups (\link colvarvalue::type_3vector \endlink type, // range (-*:*)x(-*:*)x(-*:*)) class colvar::distance_vec : public colvar::distance { public: - distance_vec (std::string const &conf); + distance_vec(std::string const &conf); distance_vec(); virtual inline ~distance_vec() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); + virtual void apply_force(colvarvalue const &force); /// Redefined to handle the box periodicity - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the box periodicity - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the box periodicity - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: distance unit vector (direction) between -/// centers of mass of two groups (colvarvalue::type_unitvector type, +/// centers of mass of two groups (colvarvalue::type_unit3vector type, /// range [-1:1]x[-1:1]x[-1:1]) class colvar::distance_dir : public colvar::distance { public: - distance_dir (std::string const &conf); + distance_dir(std::string const &conf); distance_dir(); virtual inline ~distance_dir() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: projection of the distance vector along -/// an axis (colvarvalue::type_scalar type, range (-*:*)) +/// an axis(colvarvalue::type_scalar type, range (-*:*)) class colvar::distance_z : public colvar::cvc { protected: /// Main atom group cvm::atom_group main; /// Reference atom group cvm::atom_group ref1; /// Optional, second ref atom group cvm::atom_group ref2; /// Use absolute positions, ignoring PBCs when present bool b_no_PBC; /// Compute system force on one site only to avoid unwanted /// coupling to other colvars (see e.g. Ciccotti et al., 2005) bool b_1site_force; /// Vector on which the distance vector is projected cvm::rvector axis; /// Norm of the axis cvm::real axis_norm; /// Vector distance, cached to be recycled cvm::rvector dist_v; /// Flag: using a fixed axis vector? bool fixed_axis; public: - distance_z (std::string const &conf); + distance_z(std::string const &conf); distance_z(); virtual inline ~distance_z() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; /// \brief Redefined to make use of the user-provided period - virtual void wrap (colvarvalue &x) const; + virtual void wrap(colvarvalue &x) const; }; /// \brief Colvar component: projection of the distance vector on a /// plane (colvarvalue::type_scalar type, range [0:*)) class colvar::distance_xy : public colvar::distance_z { protected: /// Components of the distance vector orthogonal to the axis cvm::rvector dist_v_ortho; /// Vector distances cvm::rvector v12, v13; public: - distance_xy (std::string const &conf); + distance_xy(std::string const &conf); distance_xy(); virtual inline ~distance_xy() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: average distance between two groups of atoms, weighted as the sixth power, -/// as in NMR refinements (colvarvalue::type_scalar type, range (0:*)) +/// as in NMR refinements(colvarvalue::type_scalar type, range (0:*)) class colvar::distance_inv : public colvar::distance { protected: /// Components of the distance vector orthogonal to the axis int exponent; public: - distance_inv (std::string const &conf); + distance_inv(std::string const &conf); distance_inv(); virtual inline ~distance_inv() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; +}; + + +/// \brief Colvar component: N1xN2 vector of pairwise distances +/// (colvarvalue::type_vector type, range (0:*) for each component) +class colvar::distance_pairs + : public colvar::cvc +{ +protected: + /// First atom group + cvm::atom_group group1; + /// Second atom group + cvm::atom_group group2; + /// Use absolute positions, ignoring PBCs when present + bool b_no_PBC; +public: + distance_pairs(std::string const &conf); + distance_pairs(); + virtual inline ~distance_pairs() {} + virtual void calc_value(); + virtual void calc_gradients(); + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: Radius of gyration of an atom group /// (colvarvalue::type_scalar type, range [0:*)) class colvar::gyration : public colvar::cvc { protected: /// Atoms involved cvm::atom_group atoms; public: /// Constructor - gyration (std::string const &conf); + gyration(std::string const &conf); gyration(); virtual inline ~gyration() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: moment of inertia of an atom group /// (colvarvalue::type_scalar type, range [0:*)) class colvar::inertia : public colvar::gyration { public: /// Constructor - inertia (std::string const &conf); + inertia(std::string const &conf); inertia(); virtual inline ~inertia() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: moment of inertia of an atom group /// around a user-defined axis (colvarvalue::type_scalar type, range [0:*)) class colvar::inertia_z : public colvar::inertia { protected: /// Vector on which the inertia tensor is projected cvm::rvector axis; public: /// Constructor - inertia_z (std::string const &conf); + inertia_z(std::string const &conf); inertia_z(); virtual inline ~inertia_z() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: projection of 3N coordinates onto an -/// eigenvector (colvarvalue::type_scalar type, range (-*:*)) +/// eigenvector(colvarvalue::type_scalar type, range (-*:*)) class colvar::eigenvector : public colvar::cvc { protected: /// Atom group cvm::atom_group atoms; /// Reference coordinates std::vector ref_pos; /// Geometric center of the reference coordinates cvm::atom_pos ref_pos_center; /// Eigenvector (of a normal or essential mode): will always have zero center std::vector eigenvec; /// Inverse square norm of the eigenvector cvm::real eigenvec_invnorm2; public: /// Constructor - eigenvector (std::string const &conf); + eigenvector(std::string const &conf); virtual inline ~eigenvector() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: angle between the centers of mass of /// three groups (colvarvalue::type_scalar type, range [0:PI]) class colvar::angle : public colvar::cvc { protected: /// Atom group cvm::atom_group group1; /// Atom group cvm::atom_group group2; /// Atom group cvm::atom_group group3; /// Inter site vectors cvm::rvector r21, r23; /// Inter site vector norms cvm::real r21l, r23l; /// Derivatives wrt group centers of mass cvm::rvector dxdr1, dxdr3; /// Compute system force on first site only to avoid unwanted /// coupling to other colvars (see e.g. Ciccotti et al., 2005) /// (or to allow dummy atoms) bool b_1site_force; public: /// Initialize by parsing the configuration - angle (std::string const &conf); + angle(std::string const &conf); /// \brief Initialize the three groups after three atoms - angle (cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3); + angle(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3); angle(); virtual inline ~angle() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: dihedral between the centers of mass of /// four groups (colvarvalue::type_scalar type, range [-PI:PI]) class colvar::dihedral : public colvar::cvc { protected: /// Atom group cvm::atom_group group1; /// Atom group cvm::atom_group group2; /// Atom group cvm::atom_group group3; /// Atom group cvm::atom_group group4; /// Inter site vectors cvm::rvector r12, r23, r34; /// \brief Compute system force on first site only to avoid unwanted /// coupling to other colvars (see e.g. Ciccotti et al., 2005) bool b_1site_force; public: /// Initialize by parsing the configuration - dihedral (std::string const &conf); + dihedral(std::string const &conf); /// \brief Initialize the four groups after four atoms - dihedral (cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3, cvm::atom const &a4); + dihedral(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3, cvm::atom const &a4); dihedral(); virtual inline ~dihedral() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); + virtual void apply_force(colvarvalue const &force); /// Redefined to handle the 2*PI periodicity - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the 2*PI periodicity - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the 2*PI periodicity - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the 2*PI periodicity - virtual void wrap (colvarvalue &x) const; + virtual void wrap(colvarvalue &x) const; }; /// \brief Colvar component: coordination number between two groups /// (colvarvalue::type_scalar type, range [0:N1*N2]) class colvar::coordnum : public colvar::distance { protected: /// \brief "Cutoff" for isotropic calculation (default) cvm::real r0; /// \brief "Cutoff vector" for anisotropic calculation cvm::rvector r0_vec; /// \brief Wheter dist/r0 or \vec{dist}*\vec{1/r0_vec} should ne be /// used bool b_anisotropic; /// Integer exponent of the function numerator int en; /// Integer exponent of the function denominator int ed; /// \brief If true, group2 will be treated as a single atom /// (default: loop over all pairs of atoms in group1 and group2) bool b_group2_center_only; public: /// Constructor - coordnum (std::string const &conf); + coordnum(std::string const &conf); coordnum(); virtual inline ~coordnum() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); + virtual void apply_force(colvarvalue const &force); template /// \brief Calculate a coordination number through the function /// (1-x**n)/(1-x**m), x = |A1-A2|/r0 \param r0 "cutoff" for the /// coordination number \param exp_num \i n exponent \param exp_den /// \i m exponent \param A1 atom \param A2 atom - static cvm::real switching_function (cvm::real const &r0, - int const &exp_num, int const &exp_den, - cvm::atom &A1, cvm::atom &A2); + static cvm::real switching_function(cvm::real const &r0, + int const &exp_num, int const &exp_den, + cvm::atom &A1, cvm::atom &A2); template /// \brief Calculate a coordination number through the function /// (1-x**n)/(1-x**m), x = |(A1-A2)*(r0_vec)^-|1 \param r0_vec /// vector of different cutoffs in the three directions \param /// exp_num \i n exponent \param exp_den \i m exponent \param A1 /// atom \param A2 atom - static cvm::real switching_function (cvm::rvector const &r0_vec, - int const &exp_num, int const &exp_den, - cvm::atom &A1, cvm::atom &A2); - - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + static cvm::real switching_function(cvm::rvector const &r0_vec, + int const &exp_num, int const &exp_den, + cvm::atom &A1, cvm::atom &A2); + + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: self-coordination number within a group /// (colvarvalue::type_scalar type, range [0:N*(N-1)/2]) class colvar::selfcoordnum : public colvar::distance { protected: /// \brief "Cutoff" for isotropic calculation (default) cvm::real r0; /// Integer exponent of the function numerator int en; /// Integer exponent of the function denominator int ed; public: /// Constructor - selfcoordnum (std::string const &conf); + selfcoordnum(std::string const &conf); selfcoordnum(); virtual inline ~selfcoordnum() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); + virtual void apply_force(colvarvalue const &force); template /// \brief Calculate a coordination number through the function /// (1-x**n)/(1-x**m), x = |A1-A2|/r0 \param r0 "cutoff" for the /// coordination number \param exp_num \i n exponent \param exp_den /// \i m exponent \param A1 atom \param A2 atom - static cvm::real switching_function (cvm::real const &r0, - int const &exp_num, int const &exp_den, - cvm::atom &A1, cvm::atom &A2); - - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + static cvm::real switching_function(cvm::real const &r0, + int const &exp_num, int const &exp_den, + cvm::atom &A1, cvm::atom &A2); + + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: hydrogen bond, defined as the product of /// a colvar::coordnum and 1/2*(1-cos((180-ang)/ang_tol)) /// (colvarvalue::type_scalar type, range [0:1]) class colvar::h_bond : public colvar::cvc { protected: /// Atoms involved in the component cvm::atom acceptor, donor; /// \brief "Cutoff" distance between acceptor and donor cvm::real r0; /// Integer exponent of the function numerator int en; /// Integer exponent of the function denominator int ed; public: - h_bond (std::string const &conf); + h_bond(std::string const &conf); /// Constructor for atoms already allocated - h_bond (cvm::atom const &acceptor, - cvm::atom const &donor, - cvm::real r0, int en, int ed); + h_bond(cvm::atom const &acceptor, + cvm::atom const &donor, + cvm::real r0, int en, int ed); h_bond(); virtual ~h_bond(); virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: alpha helix content of a contiguous /// segment of 5 or more residues, implemented as a sum of phi/psi /// dihedral angles and hydrogen bonds (colvarvalue::type_scalar type, /// range [0:1]) // class colvar::alpha_dihedrals // : public colvar::cvc // { // protected: // /// Alpha-helical reference phi value // cvm::real phi_ref; // /// Alpha-helical reference psi value // cvm::real psi_ref; // /// List of phi dihedral angles // std::vector phi; // /// List of psi dihedral angles // std::vector psi; // /// List of hydrogen bonds // std::vector hb; // public: // alpha_dihedrals (std::string const &conf); // alpha_dihedrals(); // virtual inline ~alpha_dihedrals() {} // virtual void calc_value(); // virtual void calc_gradients(); // virtual void apply_force (colvarvalue const &force); // virtual cvm::real dist2 (colvarvalue const &x1, // colvarvalue const &x2) const; // virtual colvarvalue dist2_lgrad (colvarvalue const &x1, // colvarvalue const &x2) const; // virtual colvarvalue dist2_rgrad (colvarvalue const &x1, // colvarvalue const &x2) const; // }; /// \brief Colvar component: alpha helix content of a contiguous /// segment of 5 or more residues, implemented as a sum of Ca-Ca-Ca /// angles and hydrogen bonds (colvarvalue::type_scalar type, range /// [0:1]) class colvar::alpha_angles : public colvar::cvc { protected: /// Reference Calpha-Calpha angle (default: 88 degrees) cvm::real theta_ref; /// Tolerance on the Calpha-Calpha angle cvm::real theta_tol; /// List of Calpha-Calpha angles std::vector theta; /// List of hydrogen bonds std::vector hb; /// Contribution of the hb terms cvm::real hb_coeff; public: - alpha_angles (std::string const &conf); + alpha_angles(std::string const &conf); alpha_angles(); virtual ~alpha_angles(); void calc_value(); void calc_gradients(); - void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: dihedPC /// Projection of the config onto a dihedral principal component /// See e.g. Altis et al., J. Chem. Phys 126, 244111 (2007) /// Based on a set of 'dihedral' cvcs class colvar::dihedPC : public colvar::cvc { protected: std::vector theta; std::vector coeffs; public: - dihedPC (std::string const &conf); + dihedPC(std::string const &conf); dihedPC(); virtual ~dihedPC(); void calc_value(); void calc_gradients(); - void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: orientation in space of an atom group, /// with respect to a set of reference coordinates /// (colvarvalue::type_quaternion type, range /// [-1:1]x[-1:1]x[-1:1]x[-1:1]) class colvar::orientation : public colvar::cvc { protected: /// Atom group cvm::atom_group atoms; /// Center of geometry of the group cvm::atom_pos atoms_cog; /// Reference coordinates std::vector ref_pos; /// Rotation object cvm::rotation rot; /// \brief This is used to remove jumps in the sign of the /// quaternion, which may be annoying in the colvars trajectory cvm::quaternion ref_quat; public: - orientation (std::string const &conf); + orientation(std::string const &conf); orientation(); virtual inline ~orientation() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: angle of rotation with respect to a set /// of reference coordinates (colvarvalue::type_scalar type, range /// [0:PI)) class colvar::orientation_angle : public colvar::orientation { public: - orientation_angle (std::string const &conf); + orientation_angle(std::string const &conf); orientation_angle(); virtual inline ~orientation_angle() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: cosine of the angle of rotation with respect to a set /// of reference coordinates (colvarvalue::type_scalar type, range /// [-1:1]) class colvar::orientation_proj : public colvar::orientation { public: - orientation_proj (std::string const &conf); + orientation_proj(std::string const &conf); orientation_proj(); virtual inline ~orientation_proj() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: projection of the orientation vector onto /// a predefined axis (colvarvalue::type_scalar type, range [-1:1]) class colvar::tilt : public colvar::orientation { protected: cvm::rvector axis; public: - tilt (std::string const &conf); + tilt(std::string const &conf); tilt(); virtual inline ~tilt() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; /// \brief Colvar component: angle of rotation around a predefined /// axis (colvarvalue::type_scalar type, range [-PI:PI]) class colvar::spin_angle : public colvar::orientation { protected: cvm::rvector axis; public: - spin_angle (std::string const &conf); + spin_angle(std::string const &conf); spin_angle(); virtual inline ~spin_angle() {} virtual void calc_value(); virtual void calc_gradients(); - virtual void apply_force (colvarvalue const &force); + virtual void apply_force(colvarvalue const &force); /// Redefined to handle the 2*PI periodicity - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the 2*PI periodicity - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the 2*PI periodicity - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; /// Redefined to handle the 2*PI periodicity - virtual void wrap (colvarvalue &x) const; + virtual void wrap(colvarvalue &x) const; }; /// \brief Colvar component: root mean square deviation (RMSD) of a /// group with respect to a set of reference coordinates; uses \link /// colvar::orientation \endlink to calculate the rotation matrix /// (colvarvalue::type_scalar type, range [0:*)) class colvar::rmsd : public colvar::cvc { protected: /// Atom group cvm::atom_group atoms; /// Reference coordinates (for RMSD calculation only) std::vector ref_pos; public: /// Constructor - rmsd (std::string const &conf); + rmsd(std::string const &conf); virtual inline ~rmsd() {} virtual void calc_value(); virtual void calc_gradients(); virtual void calc_force_invgrads(); virtual void calc_Jacobian_derivative(); - virtual void apply_force (colvarvalue const &force); - virtual cvm::real dist2 (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const; - virtual colvarvalue dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const; + virtual void apply_force(colvarvalue const &force); + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; }; +// \brief Colvar component: flat vector of Cartesian coordinates +// Mostly useful to compute scripted colvar values +class colvar::cartesian + : public colvar::cvc +{ +protected: + /// Atom group + cvm::atom_group atoms; +public: + cartesian(std::string const &conf); + cartesian(); + virtual inline ~cartesian() {} + virtual void calc_value(); + virtual void calc_gradients(); + virtual void apply_force(colvarvalue const &force); +}; + // metrics functions for cvc implementations // simple definitions of the distance functions; these are useful only // for optimization (the type check performed in the default // colvarcomp functions is skipped) // definitions assuming the scalar type #define simple_scalar_dist_functions(TYPE) \ \ - inline cvm::real colvar::TYPE::dist2 (colvarvalue const &x1, \ - colvarvalue const &x2) const \ + inline cvm::real colvar::TYPE::dist2(colvarvalue const &x1, \ + colvarvalue const &x2) const \ { \ return (x1.real_value - x2.real_value)*(x1.real_value - x2.real_value); \ } \ \ - inline colvarvalue colvar::TYPE::dist2_lgrad (colvarvalue const &x1, \ - colvarvalue const &x2) const \ + inline colvarvalue colvar::TYPE::dist2_lgrad(colvarvalue const &x1, \ + colvarvalue const &x2) const \ { \ return 2.0 * (x1.real_value - x2.real_value); \ } \ \ - inline colvarvalue colvar::TYPE::dist2_rgrad (colvarvalue const &x1, \ - colvarvalue const &x2) const \ + inline colvarvalue colvar::TYPE::dist2_rgrad(colvarvalue const &x1, \ + colvarvalue const &x2) const \ { \ - return this->dist2_lgrad (x2, x1); \ + return this->dist2_lgrad(x2, x1); \ } \ \ - simple_scalar_dist_functions (distance) - // NOTE: distance_z has explicit functions, see below - simple_scalar_dist_functions (distance_xy) - simple_scalar_dist_functions (distance_inv) - simple_scalar_dist_functions (angle) - simple_scalar_dist_functions (coordnum) - simple_scalar_dist_functions (selfcoordnum) - simple_scalar_dist_functions (h_bond) - simple_scalar_dist_functions (gyration) - simple_scalar_dist_functions (inertia) - simple_scalar_dist_functions (inertia_z) - simple_scalar_dist_functions (rmsd) - simple_scalar_dist_functions (orientation_angle) - simple_scalar_dist_functions (orientation_proj) - simple_scalar_dist_functions (tilt) - simple_scalar_dist_functions (eigenvector) - // simple_scalar_dist_functions (alpha_dihedrals) - simple_scalar_dist_functions (alpha_angles) - simple_scalar_dist_functions (dihedPC) +simple_scalar_dist_functions(distance) +// NOTE: distance_z has explicit functions, see below +simple_scalar_dist_functions(distance_xy) +simple_scalar_dist_functions(distance_inv) +simple_scalar_dist_functions(angle) +simple_scalar_dist_functions(coordnum) +simple_scalar_dist_functions(selfcoordnum) +simple_scalar_dist_functions(h_bond) +simple_scalar_dist_functions(gyration) +simple_scalar_dist_functions(inertia) +simple_scalar_dist_functions(inertia_z) +simple_scalar_dist_functions(rmsd) +simple_scalar_dist_functions(orientation_angle) +simple_scalar_dist_functions(orientation_proj) +simple_scalar_dist_functions(tilt) +simple_scalar_dist_functions(eigenvector) +// simple_scalar_dist_functions (alpha_dihedrals) +simple_scalar_dist_functions(alpha_angles) +simple_scalar_dist_functions(dihedPC) // metrics functions for cvc implementations with a periodicity -inline cvm::real colvar::dihedral::dist2 (colvarvalue const &x1, - colvarvalue const &x2) const +inline cvm::real colvar::dihedral::dist2(colvarvalue const &x1, + colvarvalue const &x2) const { - cvm::real diff = x1.real_value - x2.real_value; - diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); - return diff * diff; +cvm::real diff = x1.real_value - x2.real_value; +diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); +return diff * diff; } -inline colvarvalue colvar::dihedral::dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::dihedral::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - cvm::real diff = x1.real_value - x2.real_value; - diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); - return 2.0 * diff; +cvm::real diff = x1.real_value - x2.real_value; +diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); +return 2.0 * diff; } -inline colvarvalue colvar::dihedral::dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::dihedral::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - cvm::real diff = x1.real_value - x2.real_value; - diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); - return (-2.0) * diff; +cvm::real diff = x1.real_value - x2.real_value; +diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); +return (-2.0) * diff; } -inline void colvar::dihedral::wrap (colvarvalue &x) const +inline void colvar::dihedral::wrap(colvarvalue &x) const { - if ((x.real_value - wrap_center) >= 180.0) { - x.real_value -= 360.0; - return; - } +if ((x.real_value - wrap_center) >= 180.0) { +x.real_value -= 360.0; +return; +} - if ((x.real_value - wrap_center) < -180.0) { - x.real_value += 360.0; - return; - } +if ((x.real_value - wrap_center) < -180.0) { +x.real_value += 360.0; +return; +} - return; +return; } -inline cvm::real colvar::spin_angle::dist2 (colvarvalue const &x1, - colvarvalue const &x2) const +inline cvm::real colvar::spin_angle::dist2(colvarvalue const &x1, + colvarvalue const &x2) const { - cvm::real diff = x1.real_value - x2.real_value; - diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); - return diff * diff; +cvm::real diff = x1.real_value - x2.real_value; +diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); +return diff * diff; } -inline colvarvalue colvar::spin_angle::dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::spin_angle::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - cvm::real diff = x1.real_value - x2.real_value; - diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); - return 2.0 * diff; +cvm::real diff = x1.real_value - x2.real_value; +diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); +return 2.0 * diff; } -inline colvarvalue colvar::spin_angle::dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::spin_angle::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - cvm::real diff = x1.real_value - x2.real_value; - diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); - return (-2.0) * diff; +cvm::real diff = x1.real_value - x2.real_value; +diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); +return (-2.0) * diff; } -inline void colvar::spin_angle::wrap (colvarvalue &x) const +inline void colvar::spin_angle::wrap(colvarvalue &x) const { - if ((x.real_value - wrap_center) >= 180.0) { - x.real_value -= 360.0; - return; - } +if ((x.real_value - wrap_center) >= 180.0) { +x.real_value -= 360.0; +return; +} - if ((x.real_value - wrap_center) < -180.0) { - x.real_value += 360.0; - return; - } +if ((x.real_value - wrap_center) < -180.0) { +x.real_value += 360.0; +return; +} - return; +return; } // Projected distance // Differences should always be wrapped around 0 (ignoring wrap_center) -inline cvm::real colvar::distance_z::dist2 (colvarvalue const &x1, - colvarvalue const &x2) const +inline cvm::real colvar::distance_z::dist2(colvarvalue const &x1, + colvarvalue const &x2) const { cvm::real diff = x1.real_value - x2.real_value; if (period != 0.0) { - cvm::real shift = std::floor (diff/period + 0.5); + cvm::real shift = std::floor(diff/period + 0.5); diff -= shift * period; } return diff * diff; } -inline colvarvalue colvar::distance_z::dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::distance_z::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const { cvm::real diff = x1.real_value - x2.real_value; if (period != 0.0) { - cvm::real shift = std::floor (diff/period + 0.5); + cvm::real shift = std::floor(diff/period + 0.5); diff -= shift * period; } return 2.0 * diff; } -inline colvarvalue colvar::distance_z::dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::distance_z::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const { cvm::real diff = x1.real_value - x2.real_value; if (period != 0.0) { - cvm::real shift = std::floor (diff/period + 0.5); + cvm::real shift = std::floor(diff/period + 0.5); diff -= shift * period; } return (-2.0) * diff; } -inline void colvar::distance_z::wrap (colvarvalue &x) const +inline void colvar::distance_z::wrap(colvarvalue &x) const { if (! this->b_periodic) { // don't wrap if the period has not been set return; } - cvm::real shift = std::floor ((x.real_value - wrap_center) / period + 0.5); + cvm::real shift = std::floor((x.real_value - wrap_center) / period + 0.5); x.real_value -= shift * period; return; } // distance between three dimensional vectors // // TODO apply PBC to distance_vec // Note: differences should be centered around (0, 0, 0)! -inline cvm::real colvar::distance_vec::dist2 (colvarvalue const &x1, - colvarvalue const &x2) const +inline cvm::real colvar::distance_vec::dist2(colvarvalue const &x1, + colvarvalue const &x2) const { - return cvm::position_dist2 (x1.rvector_value, x2.rvector_value); + return cvm::position_dist2(x1.rvector_value, x2.rvector_value); } -inline colvarvalue colvar::distance_vec::dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::distance_vec::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const { return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value); } -inline colvarvalue colvar::distance_vec::dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::distance_vec::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const { return 2.0 * cvm::position_distance(x2.rvector_value, x1.rvector_value); } -inline cvm::real colvar::distance_dir::dist2 (colvarvalue const &x1, - colvarvalue const &x2) const +inline cvm::real colvar::distance_dir::dist2(colvarvalue const &x1, + colvarvalue const &x2) const { return (x1.rvector_value - x2.rvector_value).norm2(); } -inline colvarvalue colvar::distance_dir::dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::distance_dir::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const +{ + return colvarvalue((x1.rvector_value - x2.rvector_value), colvarvalue::type_unit3vector); +} + +inline colvarvalue colvar::distance_dir::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const +{ + return colvarvalue((x2.rvector_value - x1.rvector_value), colvarvalue::type_unit3vector); +} + +inline cvm::real colvar::distance_pairs::dist2(colvarvalue const &x1, + colvarvalue const &x2) const +{ + return (x1.vector1d_value - x2.vector1d_value).norm2(); +} + +inline colvarvalue colvar::distance_pairs::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - return colvarvalue ((x1.rvector_value - x2.rvector_value), colvarvalue::type_unitvector); + return colvarvalue((x1.vector1d_value - x2.vector1d_value), colvarvalue::type_vector); } -inline colvarvalue colvar::distance_dir::dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::distance_pairs::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - return colvarvalue ((x2.rvector_value - x1.rvector_value), colvarvalue::type_unitvector); + return colvarvalue((x2.vector1d_value - x1.vector1d_value), colvarvalue::type_vector); } + // distance between quaternions -inline cvm::real colvar::orientation::dist2 (colvarvalue const &x1, - colvarvalue const &x2) const +inline cvm::real colvar::orientation::dist2(colvarvalue const &x1, + colvarvalue const &x2) const { - return x1.quaternion_value.dist2 (x2); + return x1.quaternion_value.dist2(x2); } -inline colvarvalue colvar::orientation::dist2_lgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::orientation::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - return x1.quaternion_value.dist2_grad (x2); + return x1.quaternion_value.dist2_grad(x2); } -inline colvarvalue colvar::orientation::dist2_rgrad (colvarvalue const &x1, - colvarvalue const &x2) const +inline colvarvalue colvar::orientation::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const { - return x2.quaternion_value.dist2_grad (x1); + return x2.quaternion_value.dist2_grad(x1); } #endif diff --git a/lib/colvars/colvarcomp_angles.cpp b/lib/colvars/colvarcomp_angles.cpp index 773324240..b30041759 100644 --- a/lib/colvars/colvarcomp_angles.cpp +++ b/lib/colvars/colvarcomp_angles.cpp @@ -1,379 +1,379 @@ /// -*- c++ -*- #include "colvarmodule.h" #include "colvar.h" #include "colvarcomp.h" #include -colvar::angle::angle (std::string const &conf) - : cvc (conf) +colvar::angle::angle(std::string const &conf) + : cvc(conf) { function_type = "angle"; b_inverse_gradients = true; b_Jacobian_derivative = true; - parse_group (conf, "group1", group1); - parse_group (conf, "group2", group2); - parse_group (conf, "group3", group3); - atom_groups.push_back (&group1); - atom_groups.push_back (&group2); - atom_groups.push_back (&group3); - if (get_keyval (conf, "oneSiteSystemForce", b_1site_force, false)) { - cvm::log ("Computing system force on group 1 only"); + parse_group(conf, "group1", group1); + parse_group(conf, "group2", group2); + parse_group(conf, "group3", group3); + atom_groups.push_back(&group1); + atom_groups.push_back(&group2); + atom_groups.push_back(&group3); + if (get_keyval(conf, "oneSiteSystemForce", b_1site_force, false)) { + cvm::log("Computing system force on group 1 only"); } - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } -colvar::angle::angle (cvm::atom const &a1, +colvar::angle::angle(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3) - : group1 (std::vector (1, a1)), - group2 (std::vector (1, a2)), - group3 (std::vector (1, a3)) + : group1(std::vector (1, a1)), + group2(std::vector (1, a2)), + group3(std::vector (1, a3)) { function_type = "angle"; b_inverse_gradients = true; b_Jacobian_derivative = true; b_1site_force = false; - atom_groups.push_back (&group1); - atom_groups.push_back (&group2); - atom_groups.push_back (&group3); + atom_groups.push_back(&group1); + atom_groups.push_back(&group2); + atom_groups.push_back(&group3); - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::angle::angle() { function_type = "angle"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::angle::calc_value() { group1.read_positions(); group2.read_positions(); group3.read_positions(); cvm::atom_pos const g1_pos = group1.center_of_mass(); cvm::atom_pos const g2_pos = group2.center_of_mass(); cvm::atom_pos const g3_pos = group3.center_of_mass(); - r21 = cvm::position_distance (g2_pos, g1_pos); + r21 = cvm::position_distance(g2_pos, g1_pos); r21l = r21.norm(); - r23 = cvm::position_distance (g2_pos, g3_pos); + r23 = cvm::position_distance(g2_pos, g3_pos); r23l = r23.norm(); cvm::real const cos_theta = (r21*r23)/(r21l*r23l); - x.real_value = (180.0/PI) * std::acos (cos_theta); + x.real_value = (180.0/PI) * std::acos(cos_theta); } void colvar::angle::calc_gradients() { size_t i; cvm::real const cos_theta = (r21*r23)/(r21l*r23l); - cvm::real const dxdcos = -1.0 / std::sqrt (1.0 - cos_theta*cos_theta); + cvm::real const dxdcos = -1.0 / std::sqrt(1.0 - cos_theta*cos_theta); dxdr1 = (180.0/PI) * dxdcos * (1.0/r21l) * ( r23/r23l + (-1.0) * cos_theta * r21/r21l ); dxdr3 = (180.0/PI) * dxdcos * (1.0/r23l) * ( r21/r21l + (-1.0) * cos_theta * r23/r23l ); for (i = 0; i < group1.size(); i++) { group1[i].grad = (group1[i].mass/group1.total_mass) * (dxdr1); } for (i = 0; i < group2.size(); i++) { group2[i].grad = (group2[i].mass/group2.total_mass) * (dxdr1 + dxdr3) * (-1.0); } for (i = 0; i < group3.size(); i++) { group3[i].grad = (group3[i].mass/group3.total_mass) * (dxdr3); } } void colvar::angle::calc_force_invgrads() { // This uses a force measurement on groups 1 and 3 only // to keep in line with the implicit variable change used to // evaluate the Jacobian term (essentially polar coordinates // centered on group2, which means group2 is kept fixed // when propagating changes in the angle) if (b_1site_force) { group1.read_system_forces(); cvm::real norm_fact = 1.0 / dxdr1.norm2(); ft.real_value = norm_fact * dxdr1 * group1.system_force(); } else { group1.read_system_forces(); group3.read_system_forces(); cvm::real norm_fact = 1.0 / (dxdr1.norm2() + dxdr3.norm2()); ft.real_value = norm_fact * ( dxdr1 * group1.system_force() + dxdr3 * group3.system_force()); } return; } void colvar::angle::calc_Jacobian_derivative() { // det(J) = (2 pi) r^2 * sin(theta) // hence Jd = cot(theta) const cvm::real theta = x.real_value * PI / 180.0; jd = PI / 180.0 * (theta != 0.0 ? std::cos(theta) / std::sin(theta) : 0.0); } -void colvar::angle::apply_force (colvarvalue const &force) +void colvar::angle::apply_force(colvarvalue const &force) { if (!group1.noforce) - group1.apply_colvar_force (force.real_value); + group1.apply_colvar_force(force.real_value); if (!group2.noforce) - group2.apply_colvar_force (force.real_value); + group2.apply_colvar_force(force.real_value); if (!group3.noforce) - group3.apply_colvar_force (force.real_value); + group3.apply_colvar_force(force.real_value); } -colvar::dihedral::dihedral (std::string const &conf) - : cvc (conf) +colvar::dihedral::dihedral(std::string const &conf) + : cvc(conf) { function_type = "dihedral"; period = 360.0; b_periodic = true; b_inverse_gradients = true; b_Jacobian_derivative = true; - if (get_keyval (conf, "oneSiteSystemForce", b_1site_force, false)) { - cvm::log ("Computing system force on group 1 only"); + if (get_keyval(conf, "oneSiteSystemForce", b_1site_force, false)) { + cvm::log("Computing system force on group 1 only"); } - parse_group (conf, "group1", group1); - parse_group (conf, "group2", group2); - parse_group (conf, "group3", group3); - parse_group (conf, "group4", group4); - atom_groups.push_back (&group1); - atom_groups.push_back (&group2); - atom_groups.push_back (&group3); - atom_groups.push_back (&group4); - - x.type (colvarvalue::type_scalar); + parse_group(conf, "group1", group1); + parse_group(conf, "group2", group2); + parse_group(conf, "group3", group3); + parse_group(conf, "group4", group4); + atom_groups.push_back(&group1); + atom_groups.push_back(&group2); + atom_groups.push_back(&group3); + atom_groups.push_back(&group4); + + x.type(colvarvalue::type_scalar); } -colvar::dihedral::dihedral (cvm::atom const &a1, +colvar::dihedral::dihedral(cvm::atom const &a1, cvm::atom const &a2, cvm::atom const &a3, cvm::atom const &a4) - : group1 (std::vector (1, a1)), - group2 (std::vector (1, a2)), - group3 (std::vector (1, a3)), - group4 (std::vector (1, a4)) + : group1(std::vector (1, a1)), + group2(std::vector (1, a2)), + group3(std::vector (1, a3)), + group4(std::vector (1, a4)) { if (cvm::debug()) - cvm::log ("Initializing dihedral object from atom groups.\n"); + cvm::log("Initializing dihedral object from atom groups.\n"); function_type = "dihedral"; period = 360.0; b_periodic = true; b_inverse_gradients = true; b_Jacobian_derivative = true; b_1site_force = false; - atom_groups.push_back (&group1); - atom_groups.push_back (&group2); - atom_groups.push_back (&group3); - atom_groups.push_back (&group4); + atom_groups.push_back(&group1); + atom_groups.push_back(&group2); + atom_groups.push_back(&group3); + atom_groups.push_back(&group4); - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); if (cvm::debug()) - cvm::log ("Done initializing dihedral object from atom groups.\n"); + cvm::log("Done initializing dihedral object from atom groups.\n"); } colvar::dihedral::dihedral() { function_type = "dihedral"; period = 360.0; b_periodic = true; b_inverse_gradients = true; b_Jacobian_derivative = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::dihedral::calc_value() { group1.read_positions(); group2.read_positions(); group3.read_positions(); group4.read_positions(); cvm::atom_pos const g1_pos = group1.center_of_mass(); cvm::atom_pos const g2_pos = group2.center_of_mass(); cvm::atom_pos const g3_pos = group3.center_of_mass(); cvm::atom_pos const g4_pos = group4.center_of_mass(); // Usual sign convention: r12 = r2 - r1 - r12 = cvm::position_distance (g1_pos, g2_pos); - r23 = cvm::position_distance (g2_pos, g3_pos); - r34 = cvm::position_distance (g3_pos, g4_pos); + r12 = cvm::position_distance(g1_pos, g2_pos); + r23 = cvm::position_distance(g2_pos, g3_pos); + r34 = cvm::position_distance(g3_pos, g4_pos); - cvm::rvector const n1 = cvm::rvector::outer (r12, r23); - cvm::rvector const n2 = cvm::rvector::outer (r23, r34); + cvm::rvector const n1 = cvm::rvector::outer(r12, r23); + cvm::rvector const n2 = cvm::rvector::outer(r23, r34); cvm::real const cos_phi = n1 * n2; cvm::real const sin_phi = n1 * r34 * r23.norm(); - x.real_value = (180.0/PI) * std::atan2 (sin_phi, cos_phi); - this->wrap (x); + x.real_value = (180.0/PI) * std::atan2(sin_phi, cos_phi); + this->wrap(x); } void colvar::dihedral::calc_gradients() { - cvm::rvector A = cvm::rvector::outer (r12, r23); + cvm::rvector A = cvm::rvector::outer(r12, r23); cvm::real rA = A.norm(); - cvm::rvector B = cvm::rvector::outer (r23, r34); + cvm::rvector B = cvm::rvector::outer(r23, r34); cvm::real rB = B.norm(); - cvm::rvector C = cvm::rvector::outer (r23, A); + cvm::rvector C = cvm::rvector::outer(r23, A); cvm::real rC = C.norm(); cvm::real const cos_phi = (A*B)/(rA*rB); cvm::real const sin_phi = (C*B)/(rC*rB); cvm::rvector f1, f2, f3; rB = 1.0/rB; B *= rB; - if (std::fabs (sin_phi) > 0.1) { + if (std::fabs(sin_phi) > 0.1) { rA = 1.0/rA; A *= rA; cvm::rvector const dcosdA = rA*(cos_phi*A-B); cvm::rvector const dcosdB = rB*(cos_phi*B-A); rA = 1.0; cvm::real const K = (1.0/sin_phi) * (180.0/PI); - f1 = K * cvm::rvector::outer (r23, dcosdA); - f3 = K * cvm::rvector::outer (dcosdB, r23); - f2 = K * (cvm::rvector::outer (dcosdA, r12) - + cvm::rvector::outer (r34, dcosdB)); + f1 = K * cvm::rvector::outer(r23, dcosdA); + f3 = K * cvm::rvector::outer(dcosdB, r23); + f2 = K * (cvm::rvector::outer(dcosdA, r12) + + cvm::rvector::outer(r34, dcosdB)); } else { rC = 1.0/rC; C *= rC; cvm::rvector const dsindC = rC*(sin_phi*C-B); cvm::rvector const dsindB = rB*(sin_phi*B-C); rC = 1.0; cvm::real const K = (-1.0/cos_phi) * (180.0/PI); f1.x = K*((r23.y*r23.y + r23.z*r23.z)*dsindC.x - r23.x*r23.y*dsindC.y - r23.x*r23.z*dsindC.z); f1.y = K*((r23.z*r23.z + r23.x*r23.x)*dsindC.y - r23.y*r23.z*dsindC.z - r23.y*r23.x*dsindC.x); f1.z = K*((r23.x*r23.x + r23.y*r23.y)*dsindC.z - r23.z*r23.x*dsindC.x - r23.z*r23.y*dsindC.y); - f3 = cvm::rvector::outer (dsindB, r23); + f3 = cvm::rvector::outer(dsindB, r23); f3 *= K; f2.x = K*(-(r23.y*r12.y + r23.z*r12.z)*dsindC.x +(2.0*r23.x*r12.y - r12.x*r23.y)*dsindC.y +(2.0*r23.x*r12.z - r12.x*r23.z)*dsindC.z +dsindB.z*r34.y - dsindB.y*r34.z); f2.y = K*(-(r23.z*r12.z + r23.x*r12.x)*dsindC.y +(2.0*r23.y*r12.z - r12.y*r23.z)*dsindC.z +(2.0*r23.y*r12.x - r12.y*r23.x)*dsindC.x +dsindB.x*r34.z - dsindB.z*r34.x); f2.z = K*(-(r23.x*r12.x + r23.y*r12.y)*dsindC.z +(2.0*r23.z*r12.x - r12.z*r23.x)*dsindC.x +(2.0*r23.z*r12.y - r12.z*r23.y)*dsindC.y +dsindB.y*r34.x - dsindB.x*r34.y); } size_t i; for (i = 0; i < group1.size(); i++) group1[i].grad = (group1[i].mass/group1.total_mass) * (-f1); for (i = 0; i < group2.size(); i++) group2[i].grad = (group2[i].mass/group2.total_mass) * (-f2 + f1); for (i = 0; i < group3.size(); i++) group3[i].grad = (group3[i].mass/group3.total_mass) * (-f3 + f2); for (i = 0; i < group4.size(); i++) group4[i].grad = (group4[i].mass/group4.total_mass) * (f3); } void colvar::dihedral::calc_force_invgrads() { cvm::rvector const u12 = r12.unit(); cvm::rvector const u23 = r23.unit(); cvm::rvector const u34 = r34.unit(); cvm::real const d12 = r12.norm(); cvm::real const d34 = r34.norm(); - cvm::rvector const cross1 = (cvm::rvector::outer (u23, u12)).unit(); - cvm::rvector const cross4 = (cvm::rvector::outer (u23, u34)).unit(); + cvm::rvector const cross1 = (cvm::rvector::outer(u23, u12)).unit(); + cvm::rvector const cross4 = (cvm::rvector::outer(u23, u34)).unit(); cvm::real const dot1 = u23 * u12; cvm::real const dot4 = u23 * u34; - cvm::real const fact1 = d12 * std::sqrt (1.0 - dot1 * dot1); - cvm::real const fact4 = d34 * std::sqrt (1.0 - dot4 * dot4); + cvm::real const fact1 = d12 * std::sqrt(1.0 - dot1 * dot1); + cvm::real const fact4 = d34 * std::sqrt(1.0 - dot4 * dot4); group1.read_system_forces(); if ( b_1site_force ) { // This is only measuring the force on group 1 ft.real_value = PI/180.0 * fact1 * (cross1 * group1.system_force()); } else { // Default case: use groups 1 and 4 group4.read_system_forces(); ft.real_value = PI/180.0 * 0.5 * (fact1 * (cross1 * group1.system_force()) + fact4 * (cross4 * group4.system_force())); } } void colvar::dihedral::calc_Jacobian_derivative() { // With this choice of inverse gradient ("internal coordinates"), Jacobian correction is 0 jd = 0.0; } -void colvar::dihedral::apply_force (colvarvalue const &force) +void colvar::dihedral::apply_force(colvarvalue const &force) { if (!group1.noforce) - group1.apply_colvar_force (force.real_value); + group1.apply_colvar_force(force.real_value); if (!group2.noforce) - group2.apply_colvar_force (force.real_value); + group2.apply_colvar_force(force.real_value); if (!group3.noforce) - group3.apply_colvar_force (force.real_value); + group3.apply_colvar_force(force.real_value); if (!group4.noforce) - group4.apply_colvar_force (force.real_value); + group4.apply_colvar_force(force.real_value); } diff --git a/lib/colvars/colvarcomp_coordnums.cpp b/lib/colvars/colvarcomp_coordnums.cpp index 8b6448419..d6509aedc 100644 --- a/lib/colvars/colvarcomp_coordnums.cpp +++ b/lib/colvars/colvarcomp_coordnums.cpp @@ -1,361 +1,361 @@ /// -*- c++ -*- #include #include "colvarmodule.h" #include "colvarparse.h" #include "colvaratoms.h" #include "colvarvalue.h" #include "colvar.h" #include "colvarcomp.h" template -cvm::real colvar::coordnum::switching_function (cvm::real const &r0, +cvm::real colvar::coordnum::switching_function(cvm::real const &r0, int const &en, int const &ed, cvm::atom &A1, cvm::atom &A2) { - cvm::rvector const diff = cvm::position_distance (A1.pos, A2.pos); + cvm::rvector const diff = cvm::position_distance(A1.pos, A2.pos); cvm::real const l2 = diff.norm2()/(r0*r0); // Assume en and ed are even integers, and avoid sqrt in the following int const en2 = en/2; int const ed2 = ed/2; - cvm::real const xn = std::pow (l2, en2); - cvm::real const xd = std::pow (l2, ed2); + cvm::real const xn = std::pow(l2, en2); + cvm::real const xd = std::pow(l2, ed2); cvm::real const func = (1.0-xn)/(1.0-xd); if (calculate_gradients) { cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0); cvm::rvector const dl2dx = (2.0/(r0*r0))*diff; A1.grad += (-1.0)*dFdl2*dl2dx; A2.grad += dFdl2*dl2dx; } return func; } template -cvm::real colvar::coordnum::switching_function (cvm::rvector const &r0_vec, +cvm::real colvar::coordnum::switching_function(cvm::rvector const &r0_vec, int const &en, int const &ed, cvm::atom &A1, cvm::atom &A2) { - cvm::rvector const diff = cvm::position_distance (A1.pos, A2.pos); - cvm::rvector const scal_diff (diff.x/r0_vec.x, diff.y/r0_vec.y, diff.z/r0_vec.z); + cvm::rvector const diff = cvm::position_distance(A1.pos, A2.pos); + cvm::rvector const scal_diff(diff.x/r0_vec.x, diff.y/r0_vec.y, diff.z/r0_vec.z); cvm::real const l2 = scal_diff.norm2(); // Assume en and ed are even integers, and avoid sqrt in the following int const en2 = en/2; int const ed2 = ed/2; - cvm::real const xn = std::pow (l2, en2); - cvm::real const xd = std::pow (l2, ed2); + cvm::real const xn = std::pow(l2, en2); + cvm::real const xd = std::pow(l2, ed2); cvm::real const func = (1.0-xn)/(1.0-xd); if (calculate_gradients) { cvm::real const dFdl2 = (1.0/(1.0-xd))*(en2*(xn/l2) - func*ed2*(xd/l2))*(-1.0); - cvm::rvector const dl2dx ((2.0/(r0_vec.x*r0_vec.x))*diff.x, + cvm::rvector const dl2dx((2.0/(r0_vec.x*r0_vec.x))*diff.x, (2.0/(r0_vec.y*r0_vec.y))*diff.y, (2.0/(r0_vec.z*r0_vec.z))*diff.z); A1.grad += (-1.0)*dFdl2*dl2dx; A2.grad += dFdl2*dl2dx; } return func; } -colvar::coordnum::coordnum (std::string const &conf) - : distance (conf), b_anisotropic (false), b_group2_center_only (false) +colvar::coordnum::coordnum(std::string const &conf) + : distance(conf), b_anisotropic(false), b_group2_center_only(false) { function_type = "coordnum"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); // group1 and group2 are already initialized by distance() if (group1.b_dummy) - cvm::fatal_error ("Error: only group2 is allowed to be a dummy atom\n"); + cvm::fatal_error("Error: only group2 is allowed to be a dummy atom\n"); // need to specify this explicitly because the distance() constructor // has set it to true b_inverse_gradients = false; - bool const b_scale = get_keyval (conf, "cutoff", r0, - cvm::real (4.0 * cvm::unit_angstrom())); + bool const b_scale = get_keyval(conf, "cutoff", r0, + cvm::real(4.0 * cvm::unit_angstrom())); - if (get_keyval (conf, "cutoff3", r0_vec, - cvm::rvector (4.0, 4.0, 4.0), parse_silent)) { + if (get_keyval(conf, "cutoff3", r0_vec, + cvm::rvector(4.0, 4.0, 4.0), parse_silent)) { if (b_scale) - cvm::fatal_error ("Error: cannot specify \"scale\" and " + cvm::fatal_error("Error: cannot specify \"scale\" and " "\"scale3\" at the same time.\n"); b_anisotropic = true; // remove meaningless negative signs if (r0_vec.x < 0.0) r0_vec.x *= -1.0; if (r0_vec.y < 0.0) r0_vec.y *= -1.0; if (r0_vec.z < 0.0) r0_vec.z *= -1.0; } - get_keyval (conf, "expNumer", en, int (6) ); - get_keyval (conf, "expDenom", ed, int (12)); + get_keyval(conf, "expNumer", en, int(6) ); + get_keyval(conf, "expDenom", ed, int(12)); if ( (en%2) || (ed%2) ) { - cvm::fatal_error ("Error: odd exponents provided, can only use even ones.\n"); + cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n"); } - get_keyval (conf, "group2CenterOnly", b_group2_center_only, group2.b_dummy); + get_keyval(conf, "group2CenterOnly", b_group2_center_only, group2.b_dummy); } colvar::coordnum::coordnum() - : b_anisotropic (false), b_group2_center_only (false) + : b_anisotropic(false), b_group2_center_only(false) { function_type = "coordnum"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::coordnum::calc_value() { x.real_value = 0.0; if (b_group2_center_only) { // create a fake atom to hold the group2 com coordinates cvm::atom group2_com_atom; group2_com_atom.pos = group2.center_of_mass(); if (b_anisotropic) { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) x.real_value += switching_function (r0_vec, en, ed, *ai1, group2_com_atom); } else { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) x.real_value += switching_function (r0, en, ed, *ai1, group2_com_atom); } } else { if (b_anisotropic) { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { x.real_value += switching_function (r0_vec, en, ed, *ai1, *ai2); } } else { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { x.real_value += switching_function (r0, en, ed, *ai1, *ai2); } } } } void colvar::coordnum::calc_gradients() { if (b_group2_center_only) { // create a fake atom to hold the group2 com coordinates cvm::atom group2_com_atom; group2_com_atom.pos = group2.center_of_mass(); if (b_anisotropic) { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) switching_function (r0_vec, en, ed, *ai1, group2_com_atom); } else { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) switching_function (r0, en, ed, *ai1, group2_com_atom); } - group2.set_weighted_gradient (group2_com_atom.grad); + group2.set_weighted_gradient(group2_com_atom.grad); } else { if (b_anisotropic) { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { switching_function (r0_vec, en, ed, *ai1, *ai2); } } else { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { switching_function (r0, en, ed, *ai1, *ai2); } } } // if (cvm::debug()) { // for (size_t i = 0; i < group1.size(); i++) { - // cvm::log ("atom["+cvm::to_str (group1[i].id+1)+"] gradient: "+ + // cvm::log("atom["+cvm::to_str (group1[i].id+1)+"] gradient: "+ // cvm::to_str (group1[i].grad)+"\n"); // } // for (size_t i = 0; i < group2.size(); i++) { - // cvm::log ("atom["+cvm::to_str (group2[i].id+1)+"] gradient: "+ + // cvm::log("atom["+cvm::to_str (group2[i].id+1)+"] gradient: "+ // cvm::to_str (group2[i].grad)+"\n"); // } // } } -void colvar::coordnum::apply_force (colvarvalue const &force) +void colvar::coordnum::apply_force(colvarvalue const &force) { if (!group1.noforce) - group1.apply_colvar_force (force.real_value); + group1.apply_colvar_force(force.real_value); if (!group2.noforce) - group2.apply_colvar_force (force.real_value); + group2.apply_colvar_force(force.real_value); } // h_bond member functions -colvar::h_bond::h_bond (std::string const &conf) - : cvc (conf) +colvar::h_bond::h_bond(std::string const &conf) + : cvc(conf) { if (cvm::debug()) - cvm::log ("Initializing h_bond object.\n"); + cvm::log("Initializing h_bond object.\n"); function_type = "h_bond"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); int a_num, d_num; - get_keyval (conf, "acceptor", a_num, -1); - get_keyval (conf, "donor", d_num, -1); + get_keyval(conf, "acceptor", a_num, -1); + get_keyval(conf, "donor", d_num, -1); if ( (a_num == -1) || (d_num == -1) ) { - cvm::fatal_error ("Error: either acceptor or donor undefined.\n"); + cvm::fatal_error("Error: either acceptor or donor undefined.\n"); } - acceptor = cvm::atom (a_num); - donor = cvm::atom (d_num); - atom_groups.push_back (new cvm::atom_group); - atom_groups[0]->add_atom (acceptor); - atom_groups[0]->add_atom (donor); + acceptor = cvm::atom(a_num); + donor = cvm::atom(d_num); + atom_groups.push_back(new cvm::atom_group); + atom_groups[0]->add_atom(acceptor); + atom_groups[0]->add_atom(donor); - get_keyval (conf, "cutoff", r0, (3.3 * cvm::unit_angstrom())); - get_keyval (conf, "expNumer", en, 6); - get_keyval (conf, "expDenom", ed, 8); + get_keyval(conf, "cutoff", r0, (3.3 * cvm::unit_angstrom())); + get_keyval(conf, "expNumer", en, 6); + get_keyval(conf, "expDenom", ed, 8); if ( (en%2) || (ed%2) ) { - cvm::fatal_error ("Error: odd exponents provided, can only use even ones.\n"); + cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n"); } if (cvm::debug()) - cvm::log ("Done initializing h_bond object.\n"); + cvm::log("Done initializing h_bond object.\n"); } -colvar::h_bond::h_bond (cvm::atom const &acceptor_i, +colvar::h_bond::h_bond(cvm::atom const &acceptor_i, cvm::atom const &donor_i, cvm::real r0_i, int en_i, int ed_i) - : acceptor (acceptor_i), - donor (donor_i), - r0 (r0_i), en (en_i), ed (ed_i) + : acceptor(acceptor_i), + donor(donor_i), + r0(r0_i), en(en_i), ed(ed_i) { function_type = "h_bond"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); - atom_groups.push_back (new cvm::atom_group); - atom_groups[0]->add_atom (acceptor); - atom_groups[0]->add_atom (donor); + atom_groups.push_back(new cvm::atom_group); + atom_groups[0]->add_atom(acceptor); + atom_groups[0]->add_atom(donor); } colvar::h_bond::h_bond() - : cvc () + : cvc() { function_type = "h_bond"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::h_bond::~h_bond() { for (unsigned int i=0; i (r0, en, ed, acceptor, donor); } void colvar::h_bond::calc_gradients() { colvar::coordnum::switching_function (r0, en, ed, acceptor, donor); (*atom_groups[0])[0].grad = acceptor.grad; (*atom_groups[0])[1].grad = donor.grad; } -void colvar::h_bond::apply_force (colvarvalue const &force) +void colvar::h_bond::apply_force(colvarvalue const &force) { - acceptor.apply_force (force.real_value * acceptor.grad); + acceptor.apply_force(force.real_value * acceptor.grad); donor.apply_force (force.real_value * donor.grad); } -colvar::selfcoordnum::selfcoordnum (std::string const &conf) - : distance (conf, false) +colvar::selfcoordnum::selfcoordnum(std::string const &conf) + : distance(conf, false) { function_type = "selfcoordnum"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); // group1 is already initialized by distance() // need to specify this explicitly because the distance() constructor // has set it to true b_inverse_gradients = false; - get_keyval (conf, "cutoff", r0, cvm::real (4.0 * cvm::unit_angstrom())); - get_keyval (conf, "expNumer", en, int (6) ); - get_keyval (conf, "expDenom", ed, int (12)); + get_keyval(conf, "cutoff", r0, cvm::real(4.0 * cvm::unit_angstrom())); + get_keyval(conf, "expNumer", en, int(6) ); + get_keyval(conf, "expDenom", ed, int(12)); if ( (en%2) || (ed%2) ) { - cvm::fatal_error ("Error: odd exponents provided, can only use even ones.\n"); + cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n"); } } colvar::selfcoordnum::selfcoordnum() { function_type = "selfcoordnum"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::selfcoordnum::calc_value() { x.real_value = 0.0; for (size_t i = 0; i < group1.size() - 1; i++) for (size_t j = i + 1; j < group1.size(); j++) x.real_value += colvar::coordnum::switching_function (r0, en, ed, group1[i], group1[j]); } void colvar::selfcoordnum::calc_gradients() { for (size_t i = 0; i < group1.size() - 1; i++) for (size_t j = i + 1; j < group1.size(); j++) colvar::coordnum::switching_function (r0, en, ed, group1[i], group1[j]); } -void colvar::selfcoordnum::apply_force (colvarvalue const &force) +void colvar::selfcoordnum::apply_force(colvarvalue const &force) { if (!group1.noforce) - group1.apply_colvar_force (force.real_value); + group1.apply_colvar_force(force.real_value); } diff --git a/lib/colvars/colvarcomp_distances.cpp b/lib/colvars/colvarcomp_distances.cpp index 43bfebf18..6b9317ab2 100644 --- a/lib/colvars/colvarcomp_distances.cpp +++ b/lib/colvars/colvarcomp_distances.cpp @@ -1,1195 +1,1334 @@ /// -*- c++ -*- #include #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" #include "colvar.h" #include "colvarcomp.h" // "twogroup" flag defaults to true; set to false by selfCoordNum // (only distance-derived component based on only one group) -colvar::distance::distance (std::string const &conf, bool twogroups) - : cvc (conf) +colvar::distance::distance(std::string const &conf, bool twogroups) + : cvc(conf) { function_type = "distance"; b_inverse_gradients = true; b_Jacobian_derivative = true; - if (get_keyval (conf, "forceNoPBC", b_no_PBC, false)) { - cvm::log ("Computing distance using absolute positions (not minimal-image)"); + if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) { + cvm::log("Computing distance using absolute positions (not minimal-image)"); } - if (twogroups && get_keyval (conf, "oneSiteSystemForce", b_1site_force, false)) { - cvm::log ("Computing system force on group 1 only"); + if (twogroups && get_keyval(conf, "oneSiteSystemForce", b_1site_force, false)) { + cvm::log("Computing system force on group 1 only"); } - parse_group (conf, "group1", group1); - atom_groups.push_back (&group1); + parse_group(conf, "group1", group1); + atom_groups.push_back(&group1); if (twogroups) { - parse_group (conf, "group2", group2); - atom_groups.push_back (&group2); + parse_group(conf, "group2", group2); + atom_groups.push_back(&group2); } - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::distance::distance() - : cvc () + : cvc() { function_type = "distance"; b_inverse_gradients = true; b_Jacobian_derivative = true; b_1site_force = false; b_no_PBC = false; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::distance::calc_value() { if (b_no_PBC) { dist_v = group2.center_of_mass() - group1.center_of_mass(); } else { - dist_v = cvm::position_distance (group1.center_of_mass(), + dist_v = cvm::position_distance(group1.center_of_mass(), group2.center_of_mass()); } x.real_value = dist_v.norm(); } void colvar::distance::calc_gradients() { cvm::rvector const u = dist_v.unit(); - group1.set_weighted_gradient (-1.0 * u); - group2.set_weighted_gradient ( u); + group1.set_weighted_gradient(-1.0 * u); + group2.set_weighted_gradient( u); } void colvar::distance::calc_force_invgrads() { group1.read_system_forces(); if ( b_1site_force ) { ft.real_value = -1.0 * (group1.system_force() * dist_v.unit()); } else { group2.read_system_forces(); ft.real_value = 0.5 * ((group2.system_force() - group1.system_force()) * dist_v.unit()); } } void colvar::distance::calc_Jacobian_derivative() { jd.real_value = x.real_value ? (2.0 / x.real_value) : 0.0; } -void colvar::distance::apply_force (colvarvalue const &force) +void colvar::distance::apply_force(colvarvalue const &force) { if (!group1.noforce) - group1.apply_colvar_force (force.real_value); + group1.apply_colvar_force(force.real_value); if (!group2.noforce) - group2.apply_colvar_force (force.real_value); + group2.apply_colvar_force(force.real_value); } -colvar::distance_vec::distance_vec (std::string const &conf) - : distance (conf) +colvar::distance_vec::distance_vec(std::string const &conf) + : distance(conf) { function_type = "distance_vec"; - x.type (colvarvalue::type_vector); + x.type(colvarvalue::type_3vector); } colvar::distance_vec::distance_vec() : distance() { function_type = "distance_vec"; - x.type (colvarvalue::type_vector); + x.type(colvarvalue::type_3vector); } void colvar::distance_vec::calc_value() { if (b_no_PBC) { x.rvector_value = group2.center_of_mass() - group1.center_of_mass(); } else { - x.rvector_value = cvm::position_distance (group1.center_of_mass(), + x.rvector_value = cvm::position_distance(group1.center_of_mass(), group2.center_of_mass()); } } void colvar::distance_vec::calc_gradients() { // gradients are not stored: a 3x3 matrix for each atom would be // needed to store just the identity matrix } -void colvar::distance_vec::apply_force (colvarvalue const &force) +void colvar::distance_vec::apply_force(colvarvalue const &force) { if (!group1.noforce) - group1.apply_force (-1.0 * force.rvector_value); + group1.apply_force(-1.0 * force.rvector_value); if (!group2.noforce) - group2.apply_force ( force.rvector_value); + group2.apply_force( force.rvector_value); } -colvar::distance_z::distance_z (std::string const &conf) - : cvc (conf) +colvar::distance_z::distance_z(std::string const &conf) + : cvc(conf) { function_type = "distance_z"; b_inverse_gradients = true; b_Jacobian_derivative = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); // TODO detect PBC from MD engine (in simple cases) // and then update period in real time if (period != 0.0) b_periodic = true; if ((wrap_center != 0.0) && (period == 0.0)) { - cvm::error ("Error: wrapAround was defined in a distanceZ component," + cvm::error("Error: wrapAround was defined in a distanceZ component," " but its period has not been set.\n"); return; } - parse_group (conf, "main", main); - parse_group (conf, "ref", ref1); - atom_groups.push_back (&main); - atom_groups.push_back (&ref1); + parse_group(conf, "main", main); + parse_group(conf, "ref", ref1); + atom_groups.push_back(&main); + atom_groups.push_back(&ref1); // this group is optional - parse_group (conf, "ref2", ref2, true); + parse_group(conf, "ref2", ref2, true); if (ref2.size()) { - atom_groups.push_back (&ref2); - cvm::log ("Using axis joining the centers of mass of groups \"ref\" and \"ref2\""); + atom_groups.push_back(&ref2); + cvm::log("Using axis joining the centers of mass of groups \"ref\" and \"ref2\""); fixed_axis = false; - if (key_lookup (conf, "axis")) - cvm::log ("Warning: explicit axis definition will be ignored!"); + if (key_lookup(conf, "axis")) + cvm::log("Warning: explicit axis definition will be ignored!"); } else { - if (get_keyval (conf, "axis", axis, cvm::rvector (0.0, 0.0, 1.0))) { + if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) { if (axis.norm2() == 0.0) { - cvm::error ("Axis vector is zero!"); + cvm::error("Axis vector is zero!"); return; } if (axis.norm2() != 1.0) { axis = axis.unit(); - cvm::log ("The normalized axis is: "+cvm::to_str (axis)+".\n"); + cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n"); } } fixed_axis = true; } - if (get_keyval (conf, "forceNoPBC", b_no_PBC, false)) { - cvm::log ("Computing distance using absolute positions (not minimal-image)"); + if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) { + cvm::log("Computing distance using absolute positions (not minimal-image)"); } - if (get_keyval (conf, "oneSiteSystemForce", b_1site_force, false)) { - cvm::log ("Computing system force on group \"main\" only"); + if (get_keyval(conf, "oneSiteSystemForce", b_1site_force, false)) { + cvm::log("Computing system force on group \"main\" only"); } } colvar::distance_z::distance_z() { function_type = "distance_z"; b_inverse_gradients = true; b_Jacobian_derivative = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::distance_z::calc_value() { if (fixed_axis) { if (b_no_PBC) { dist_v = main.center_of_mass() - ref1.center_of_mass(); } else { - dist_v = cvm::position_distance (ref1.center_of_mass(), + dist_v = cvm::position_distance(ref1.center_of_mass(), main.center_of_mass()); } } else { if (b_no_PBC) { dist_v = main.center_of_mass() - (0.5 * (ref1.center_of_mass() + ref2.center_of_mass())); axis = ref2.center_of_mass() - ref1.center_of_mass(); } else { - dist_v = cvm::position_distance (0.5 * (ref1.center_of_mass() + + dist_v = cvm::position_distance(0.5 * (ref1.center_of_mass() + ref2.center_of_mass()), main.center_of_mass()); - axis = cvm::position_distance (ref1.center_of_mass(), ref2.center_of_mass()); + axis = cvm::position_distance(ref1.center_of_mass(), ref2.center_of_mass()); } axis_norm = axis.norm(); axis = axis.unit(); } x.real_value = axis * dist_v; - this->wrap (x); + this->wrap(x); } void colvar::distance_z::calc_gradients() { - main.set_weighted_gradient ( axis ); + main.set_weighted_gradient( axis ); if (fixed_axis) { - ref1.set_weighted_gradient (-1.0 * axis); + ref1.set_weighted_gradient(-1.0 * axis); } else { if (b_no_PBC) { - ref1.set_weighted_gradient ( 1.0 / axis_norm * (main.center_of_mass() - ref2.center_of_mass() - + ref1.set_weighted_gradient( 1.0 / axis_norm * (main.center_of_mass() - ref2.center_of_mass() - x.real_value * axis )); - ref2.set_weighted_gradient ( 1.0 / axis_norm * (ref1.center_of_mass() - main.center_of_mass() + + ref2.set_weighted_gradient( 1.0 / axis_norm * (ref1.center_of_mass() - main.center_of_mass() + x.real_value * axis )); } else { - ref1.set_weighted_gradient ( 1.0 / axis_norm * ( - cvm::position_distance (ref2.center_of_mass(), main.center_of_mass()) - x.real_value * axis )); - ref2.set_weighted_gradient ( 1.0 / axis_norm * ( - cvm::position_distance (main.center_of_mass(), ref1.center_of_mass()) + x.real_value * axis )); + ref1.set_weighted_gradient( 1.0 / axis_norm * ( + cvm::position_distance(ref2.center_of_mass(), main.center_of_mass()) - x.real_value * axis )); + ref2.set_weighted_gradient( 1.0 / axis_norm * ( + cvm::position_distance(main.center_of_mass(), ref1.center_of_mass()) + x.real_value * axis )); } } if (b_debug_gradients) { - cvm::log ("Debugging gradients for group main:\n"); - debug_gradients (main); - cvm::log ("Debugging gradients for group ref1:\n"); - debug_gradients (ref1); - cvm::log ("Debugging gradients for group ref2:\n"); - debug_gradients (ref2); + cvm::log("Debugging gradients for group main:\n"); + debug_gradients(main); + cvm::log("Debugging gradients for group ref1:\n"); + debug_gradients(ref1); + cvm::log("Debugging gradients for group ref2:\n"); + debug_gradients(ref2); } } void colvar::distance_z::calc_force_invgrads() { main.read_system_forces(); if (fixed_axis && !b_1site_force) { ref1.read_system_forces(); ft.real_value = 0.5 * ((main.system_force() - ref1.system_force()) * axis); } else { ft.real_value = main.system_force() * axis; } } void colvar::distance_z::calc_Jacobian_derivative() { jd.real_value = 0.0; } -void colvar::distance_z::apply_force (colvarvalue const &force) +void colvar::distance_z::apply_force(colvarvalue const &force) { if (!ref1.noforce) - ref1.apply_colvar_force (force.real_value); + ref1.apply_colvar_force(force.real_value); if (ref2.size() && !ref2.noforce) - ref2.apply_colvar_force (force.real_value); + ref2.apply_colvar_force(force.real_value); if (!main.noforce) - main.apply_colvar_force (force.real_value); + main.apply_colvar_force(force.real_value); } -colvar::distance_xy::distance_xy (std::string const &conf) - : distance_z (conf) +colvar::distance_xy::distance_xy(std::string const &conf) + : distance_z(conf) { function_type = "distance_xy"; b_inverse_gradients = true; b_Jacobian_derivative = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::distance_xy::distance_xy() : distance_z() { function_type = "distance_xy"; b_inverse_gradients = true; b_Jacobian_derivative = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::distance_xy::calc_value() { if (b_no_PBC) { dist_v = main.center_of_mass() - ref1.center_of_mass(); } else { - dist_v = cvm::position_distance (ref1.center_of_mass(), + dist_v = cvm::position_distance(ref1.center_of_mass(), main.center_of_mass()); } if (!fixed_axis) { if (b_no_PBC) { v12 = ref2.center_of_mass() - ref1.center_of_mass(); } else { - v12 = cvm::position_distance (ref1.center_of_mass(), ref2.center_of_mass()); + v12 = cvm::position_distance(ref1.center_of_mass(), ref2.center_of_mass()); } axis_norm = v12.norm(); axis = v12.unit(); } dist_v_ortho = dist_v - (dist_v * axis) * axis; x.real_value = dist_v_ortho.norm(); } void colvar::distance_xy::calc_gradients() { // Intermediate quantity (r_P3 / r_12 where P is the projection - // of 3 (main) on the plane orthogonal to 12, containing 1 (ref1)) + // of 3(main) on the plane orthogonal to 12, containing 1 (ref1)) cvm::real A; cvm::real x_inv; if (x.real_value == 0.0) return; x_inv = 1.0 / x.real_value; if (fixed_axis) { - ref1.set_weighted_gradient (-1.0 * x_inv * dist_v_ortho); - main.set_weighted_gradient ( x_inv * dist_v_ortho); + ref1.set_weighted_gradient(-1.0 * x_inv * dist_v_ortho); + main.set_weighted_gradient( x_inv * dist_v_ortho); } else { if (b_no_PBC) { v13 = main.center_of_mass() - ref1.center_of_mass(); } else { - v13 = cvm::position_distance (ref1.center_of_mass(), main.center_of_mass()); + v13 = cvm::position_distance(ref1.center_of_mass(), main.center_of_mass()); } A = (dist_v * axis) / axis_norm; - ref1.set_weighted_gradient ( (A - 1.0) * x_inv * dist_v_ortho); - ref2.set_weighted_gradient ( -A * x_inv * dist_v_ortho); - main.set_weighted_gradient ( 1.0 * x_inv * dist_v_ortho); + ref1.set_weighted_gradient( (A - 1.0) * x_inv * dist_v_ortho); + ref2.set_weighted_gradient( -A * x_inv * dist_v_ortho); + main.set_weighted_gradient( 1.0 * x_inv * dist_v_ortho); } } void colvar::distance_xy::calc_force_invgrads() { main.read_system_forces(); if (fixed_axis && !b_1site_force) { ref1.read_system_forces(); ft.real_value = 0.5 / x.real_value * ((main.system_force() - ref1.system_force()) * dist_v_ortho); } else { ft.real_value = 1.0 / x.real_value * main.system_force() * dist_v_ortho; } } void colvar::distance_xy::calc_Jacobian_derivative() { jd.real_value = x.real_value ? (1.0 / x.real_value) : 0.0; } -void colvar::distance_xy::apply_force (colvarvalue const &force) +void colvar::distance_xy::apply_force(colvarvalue const &force) { if (!ref1.noforce) - ref1.apply_colvar_force (force.real_value); + ref1.apply_colvar_force(force.real_value); if (ref2.size() && !ref2.noforce) - ref2.apply_colvar_force (force.real_value); + ref2.apply_colvar_force(force.real_value); if (!main.noforce) - main.apply_colvar_force (force.real_value); + main.apply_colvar_force(force.real_value); } -colvar::distance_dir::distance_dir (std::string const &conf) - : distance (conf) +colvar::distance_dir::distance_dir(std::string const &conf) + : distance(conf) { function_type = "distance_dir"; - x.type (colvarvalue::type_unitvector); + x.type(colvarvalue::type_unit3vector); } colvar::distance_dir::distance_dir() : distance() { function_type = "distance_dir"; - x.type (colvarvalue::type_unitvector); + x.type(colvarvalue::type_unit3vector); } void colvar::distance_dir::calc_value() { if (b_no_PBC) { dist_v = group2.center_of_mass() - group1.center_of_mass(); } else { - dist_v = cvm::position_distance (group1.center_of_mass(), + dist_v = cvm::position_distance(group1.center_of_mass(), group2.center_of_mass()); } x.rvector_value = dist_v.unit(); } void colvar::distance_dir::calc_gradients() { // gradients are computed on the fly within apply_force() // Note: could be a problem if a future bias relies on gradient // calculations... } -void colvar::distance_dir::apply_force (colvarvalue const &force) +void colvar::distance_dir::apply_force(colvarvalue const &force) { // remove the radial force component cvm::real const iprod = force.rvector_value * x.rvector_value; cvm::rvector const force_tang = force.rvector_value - iprod * x.rvector_value; if (!group1.noforce) - group1.apply_force (-1.0 * force_tang); + group1.apply_force(-1.0 * force_tang); if (!group2.noforce) - group2.apply_force ( force_tang); + group2.apply_force( force_tang); } -colvar::distance_inv::distance_inv (std::string const &conf) - : distance (conf) +colvar::distance_inv::distance_inv(std::string const &conf) + : distance(conf) { function_type = "distance_inv"; - get_keyval (conf, "exponent", exponent, 6); + get_keyval(conf, "exponent", exponent, 6); if (exponent%2) { - cvm::error ("Error: odd exponent provided, can only use even ones.\n"); + cvm::error("Error: odd exponent provided, can only use even ones.\n"); return; } if (exponent <= 0) { - cvm::error ("Error: negative or zero exponent provided.\n"); + cvm::error("Error: negative or zero exponent provided.\n"); return; } for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) { for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { if (ai1->id == ai2->id) - cvm::error ("Error: group1 and group1 have some atoms in common: this is not allowed for distanceInv.\n"); + cvm::error("Error: group1 and group1 have some atoms in common: this is not allowed for distanceInv.\n"); return; } } b_inverse_gradients = false; b_Jacobian_derivative = false; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::distance_inv::distance_inv() { function_type = "distance_inv"; exponent = 6; b_inverse_gradients = false; b_Jacobian_derivative = false; b_1site_force = false; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::distance_inv::calc_value() { x.real_value = 0.0; if (b_no_PBC) { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) { for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { cvm::rvector const dv = ai2->pos - ai1->pos; cvm::real const d2 = dv.norm2(); cvm::real dinv = 1.0; for (int ne = 0; ne < exponent/2; ne++) dinv *= 1.0/d2; x.real_value += dinv; - cvm::rvector const dsumddv = -(cvm::real (exponent)) * dinv/d2 * dv; + cvm::rvector const dsumddv = -(cvm::real(exponent)) * dinv/d2 * dv; ai1->grad += -1.0 * dsumddv; ai2->grad += dsumddv; } } } else { for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) { for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { - cvm::rvector const dv = cvm::position_distance (ai1->pos, ai2->pos); + cvm::rvector const dv = cvm::position_distance(ai1->pos, ai2->pos); cvm::real const d2 = dv.norm2(); cvm::real dinv = 1.0; for (int ne = 0; ne < exponent/2; ne++) dinv *= 1.0/d2; x.real_value += dinv; - cvm::rvector const dsumddv = -(cvm::real (exponent)) * dinv/d2 * dv; + cvm::rvector const dsumddv = -(cvm::real(exponent)) * dinv/d2 * dv; ai1->grad += -1.0 * dsumddv; ai2->grad += dsumddv; } } } - x.real_value *= 1.0 / cvm::real (group1.size() * group2.size()); - x.real_value = std::pow (x.real_value, -1.0/(cvm::real (exponent))); + x.real_value *= 1.0 / cvm::real(group1.size() * group2.size()); + x.real_value = std::pow(x.real_value, -1.0/(cvm::real(exponent))); } void colvar::distance_inv::calc_gradients() { - cvm::real const dxdsum = (-1.0/(cvm::real (exponent))) * std::pow (x.real_value, exponent+1) / cvm::real (group1.size() * group2.size()); + cvm::real const dxdsum = (-1.0/(cvm::real(exponent))) * std::pow(x.real_value, exponent+1) / cvm::real(group1.size() * group2.size()); for (cvm::atom_iter ai1 = group1.begin(); ai1 != group1.end(); ai1++) { ai1->grad *= dxdsum; } for (cvm::atom_iter ai2 = group2.begin(); ai2 != group2.end(); ai2++) { ai2->grad *= dxdsum; } } -void colvar::distance_inv::apply_force (colvarvalue const &force) +void colvar::distance_inv::apply_force(colvarvalue const &force) { if (!group1.noforce) - group1.apply_colvar_force (force.real_value); + group1.apply_colvar_force(force.real_value); if (!group2.noforce) - group2.apply_colvar_force (force.real_value); + group2.apply_colvar_force(force.real_value); } -colvar::gyration::gyration (std::string const &conf) - : cvc (conf) +colvar::distance_pairs::distance_pairs(std::string const &conf) + : cvc(conf) +{ + function_type = "distance_pairs"; + b_inverse_gradients = false; + b_Jacobian_derivative = false; + + if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) { + cvm::log("Computing distance using absolute positions (not minimal-image)"); + } + + parse_group(conf, "group1", group1); + atom_groups.push_back(&group1); + + parse_group(conf, "group2", group2); + atom_groups.push_back(&group2); + + x.type(colvarvalue::type_vector); + x.vector1d_value.resize(group1.size() * group2.size()); +} + + +colvar::distance_pairs::distance_pairs() +{ + function_type = "distance_pairs"; + b_inverse_gradients = false; + b_Jacobian_derivative = false; + x.type(colvarvalue::type_vector); +} + + +void colvar::distance_pairs::calc_value() +{ + x.vector1d_value.resize(group1.size() * group2.size()); + + if (b_no_PBC) { + size_t i1, i2; + for (i1 = 0; i1 < group1.size(); i1++) { + for (i2 = 0; i2 < group2.size(); i2++) { + cvm::rvector const dv = group2[i2].pos - group1[i1].pos; + cvm::real const d = dv.norm(); + x.vector1d_value[i1*group2.size() + i2] = d; + group1[i1].grad = -1.0 * dv.unit(); + group2[i2].grad = dv.unit(); + } + } + } else { + size_t i1, i2; + for (i1 = 0; i1 < group1.size(); i1++) { + for (i2 = 0; i2 < group2.size(); i2++) { + cvm::rvector const dv = cvm::position_distance(group1[i1].pos, group2[i2].pos); + cvm::real const d = dv.norm(); + x.vector1d_value[i1*group2.size() + i2] = d; + group1[i1].grad = -1.0 * dv.unit(); + group2[i2].grad = dv.unit(); + } + } + } +} + +void colvar::distance_pairs::calc_gradients() +{ + // will be calculated on the fly in apply_force() + if (b_debug_gradients) { + cvm::log("Debugging gradients:\n"); + debug_gradients(group1); + } +} + +void colvar::distance_pairs::apply_force(colvarvalue const &force) +{ + if (b_no_PBC) { + size_t i1, i2; + for (i1 = 0; i1 < group1.size(); i1++) { + for (i2 = 0; i2 < group2.size(); i2++) { + cvm::rvector const dv = group2[i2].pos - group1[i1].pos; + group1[i1].apply_force(force[i1*group2.size() + i2] * (-1.0) * dv.unit()); + group2[i2].apply_force(force[i1*group2.size() + i2] * dv.unit()); + } + } + } else { + size_t i1, i2; + for (i1 = 0; i1 < group1.size(); i1++) { + for (i2 = 0; i2 < group2.size(); i2++) { + cvm::rvector const dv = cvm::position_distance(group1[i1].pos, group2[i2].pos); + group1[i1].apply_force(force[i1*group2.size() + i2] * (-1.0) * dv.unit()); + group2[i2].apply_force(force[i1*group2.size() + i2] * dv.unit()); + } + } + } +} + + +colvar::gyration::gyration(std::string const &conf) + : cvc(conf) { function_type = "gyration"; b_inverse_gradients = true; b_Jacobian_derivative = true; - parse_group (conf, "atoms", atoms); - atom_groups.push_back (&atoms); + parse_group(conf, "atoms", atoms); + atom_groups.push_back(&atoms); if (atoms.b_user_defined_fit) { - cvm::log ("WARNING: explicit fitting parameters were provided for atom group \"atoms\"."); + cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\"."); } else { atoms.b_center = true; - atoms.ref_pos.assign (1, cvm::atom_pos (0.0, 0.0, 0.0)); + atoms.ref_pos.assign(1, cvm::atom_pos(0.0, 0.0, 0.0)); } - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::gyration::gyration() { function_type = "gyration"; b_inverse_gradients = true; b_Jacobian_derivative = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::gyration::calc_value() { x.real_value = 0.0; for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) { x.real_value += (ai->pos).norm2(); } - x.real_value = std::sqrt (x.real_value / cvm::real (atoms.size())); + x.real_value = std::sqrt(x.real_value / cvm::real(atoms.size())); } void colvar::gyration::calc_gradients() { - cvm::real const drdx = 1.0/(cvm::real (atoms.size()) * x.real_value); + cvm::real const drdx = 1.0/(cvm::real(atoms.size()) * x.real_value); for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) { ai->grad = drdx * ai->pos; } if (b_debug_gradients) { - cvm::log ("Debugging gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging gradients:\n"); + debug_gradients(atoms); } } void colvar::gyration::calc_force_invgrads() { atoms.read_system_forces(); cvm::real const dxdr = 1.0/x.real_value; ft.real_value = 0.0; for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) { ft.real_value += dxdr * ai->pos * ai->system_force; } } void colvar::gyration::calc_Jacobian_derivative() { - jd = x.real_value ? (3.0 * cvm::real (atoms.size()) - 4.0) / x.real_value : 0.0; + jd = x.real_value ? (3.0 * cvm::real(atoms.size()) - 4.0) / x.real_value : 0.0; } -void colvar::gyration::apply_force (colvarvalue const &force) +void colvar::gyration::apply_force(colvarvalue const &force) { if (!atoms.noforce) - atoms.apply_colvar_force (force.real_value); + atoms.apply_colvar_force(force.real_value); } -colvar::inertia::inertia (std::string const &conf) - : gyration (conf) +colvar::inertia::inertia(std::string const &conf) + : gyration(conf) { function_type = "inertia"; b_inverse_gradients = false; b_Jacobian_derivative = false; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::inertia::inertia() { function_type = "inertia"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::inertia::calc_value() { x.real_value = 0.0; for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) { x.real_value += (ai->pos).norm2(); } } void colvar::inertia::calc_gradients() { for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) { ai->grad = 2.0 * ai->pos; } if (b_debug_gradients) { - cvm::log ("Debugging gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging gradients:\n"); + debug_gradients(atoms); } } -void colvar::inertia::apply_force (colvarvalue const &force) +void colvar::inertia::apply_force(colvarvalue const &force) { if (!atoms.noforce) - atoms.apply_colvar_force (force.real_value); + atoms.apply_colvar_force(force.real_value); } -colvar::inertia_z::inertia_z (std::string const &conf) - : inertia (conf) +colvar::inertia_z::inertia_z(std::string const &conf) + : inertia(conf) { function_type = "inertia_z"; - if (get_keyval (conf, "axis", axis, cvm::rvector (0.0, 0.0, 1.0))) { + if (get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0))) { if (axis.norm2() == 0.0) { - cvm::error ("Axis vector is zero!"); + cvm::error("Axis vector is zero!"); return; } if (axis.norm2() != 1.0) { axis = axis.unit(); - cvm::log ("The normalized axis is: "+cvm::to_str (axis)+".\n"); + cvm::log("The normalized axis is: "+cvm::to_str(axis)+".\n"); } } - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::inertia_z::inertia_z() { function_type = "inertia_z"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::inertia_z::calc_value() { x.real_value = 0.0; for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) { cvm::real const iprod = ai->pos * axis; x.real_value += iprod * iprod; } } void colvar::inertia_z::calc_gradients() { for (cvm::atom_iter ai = atoms.begin(); ai != atoms.end(); ai++) { ai->grad = 2.0 * (ai->pos * axis) * axis; } if (b_debug_gradients) { - cvm::log ("Debugging gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging gradients:\n"); + debug_gradients(atoms); } } -void colvar::inertia_z::apply_force (colvarvalue const &force) +void colvar::inertia_z::apply_force(colvarvalue const &force) { if (!atoms.noforce) - atoms.apply_colvar_force (force.real_value); + atoms.apply_colvar_force(force.real_value); } -colvar::rmsd::rmsd (std::string const &conf) - : cvc (conf) +colvar::rmsd::rmsd(std::string const &conf) + : cvc(conf) { b_inverse_gradients = true; b_Jacobian_derivative = true; function_type = "rmsd"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); - parse_group (conf, "atoms", atoms); - atom_groups.push_back (&atoms); + parse_group(conf, "atoms", atoms); + atom_groups.push_back(&atoms); if (atoms.b_dummy) { - cvm::error ("Error: \"atoms\" cannot be a dummy atom."); + cvm::error("Error: \"atoms\" cannot be a dummy atom."); return; } if (atoms.ref_pos_group != NULL && b_Jacobian_derivative) { - cvm::log ("The option \"refPositionsGroup\" (alternative group for fitting) was enabled: " + 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; } // the following is a simplified version of the corresponding atom group options; // we need this because the reference coordinates defined inside the atom group // may be used only for fitting, and even more so if ref_pos_group is used - if (get_keyval (conf, "refPositions", ref_pos, ref_pos)) { - cvm::log ("Using reference positions from configuration file to calculate the variable.\n"); + if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) { + cvm::log("Using reference positions from configuration file to calculate the variable.\n"); if (ref_pos.size() != atoms.size()) { - cvm::error ("Error: the number of reference positions provided ("+ - cvm::to_str (ref_pos.size())+ + cvm::error("Error: the number of reference positions provided ("+ + cvm::to_str(ref_pos.size())+ ") does not match the number of atoms of group \"atoms\" ("+ - cvm::to_str (atoms.size())+").\n"); + cvm::to_str(atoms.size())+").\n"); return; } } { std::string ref_pos_file; - if (get_keyval (conf, "refPositionsFile", ref_pos_file, std::string (""))) { + if (get_keyval(conf, "refPositionsFile", ref_pos_file, std::string(""))) { if (ref_pos.size()) { - cvm::error ("Error: cannot specify \"refPositionsFile\" and " + cvm::error("Error: cannot specify \"refPositionsFile\" and " "\"refPositions\" at the same time.\n"); return; } std::string ref_pos_col; double ref_pos_col_value; - if (get_keyval (conf, "refPositionsCol", ref_pos_col, std::string (""))) { + if (get_keyval(conf, "refPositionsCol", ref_pos_col, std::string(""))) { // if provided, use PDB column to select coordinates - bool found = get_keyval (conf, "refPositionsColValue", ref_pos_col_value, 0.0); + bool found = get_keyval(conf, "refPositionsColValue", ref_pos_col_value, 0.0); if (found && !ref_pos_col_value) - cvm::error ("Error: refPositionsColValue, " + cvm::error("Error: refPositionsColValue, " "if provided, must be non-zero.\n"); return; } else { // if not, rely on existing atom indices for the group atoms.create_sorted_ids(); } - ref_pos.resize (atoms.size()); - cvm::load_coords (ref_pos_file.c_str(), ref_pos, atoms.sorted_ids, + ref_pos.resize(atoms.size()); + cvm::load_coords(ref_pos_file.c_str(), ref_pos, atoms.sorted_ids, ref_pos_col, ref_pos_col_value); } } if (atoms.b_user_defined_fit) { - cvm::log ("WARNING: explicit fitting parameters were provided for atom group \"atoms\"."); + cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\"."); } else { // Default: fit everything - cvm::log ("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating it as a variable: " + cvm::log("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating it as a variable: " "if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n"); atoms.b_center = true; atoms.b_rotate = true; // default case: reference positions for calculating the rmsd are also those used // for fitting atoms.ref_pos = ref_pos; atoms.center_ref_pos(); - cvm::log ("This is a standard minimum RMSD, derivatives of the optimal rotation " + 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()); + atoms.rot.request_group1_gradients(atoms.size()); // request derivatives of optimal rotation wrt reference coordinates for Jacobian: - atoms.rot.request_group2_gradients (atoms.size()); + atoms.rot.request_group2_gradients(atoms.size()); } } void colvar::rmsd::calc_value() { // rotational-translational fit is handled by the atom group x.real_value = 0.0; for (size_t ia = 0; ia < atoms.size(); ia++) { x.real_value += (atoms[ia].pos - ref_pos[ia]).norm2(); } - x.real_value /= cvm::real (atoms.size()); // MSD - x.real_value = std::sqrt (x.real_value); + x.real_value /= cvm::real(atoms.size()); // MSD + x.real_value = std::sqrt(x.real_value); } void colvar::rmsd::calc_gradients() { cvm::real const drmsddx2 = (x.real_value > 0.0) ? - 0.5 / (x.real_value * cvm::real (atoms.size())) : + 0.5 / (x.real_value * cvm::real(atoms.size())) : 0.0; for (size_t ia = 0; ia < atoms.size(); ia++) { atoms[ia].grad = (drmsddx2 * 2.0 * (atoms[ia].pos - ref_pos[ia])); } if (b_debug_gradients) { - cvm::log ("Debugging gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging gradients:\n"); + debug_gradients(atoms); } } -void colvar::rmsd::apply_force (colvarvalue const &force) +void colvar::rmsd::apply_force(colvarvalue const &force) { if (!atoms.noforce) - atoms.apply_colvar_force (force.real_value); + atoms.apply_colvar_force(force.real_value); } void colvar::rmsd::calc_force_invgrads() { atoms.read_system_forces(); ft.real_value = 0.0; // Note: gradient square norm is 1/N_atoms for (size_t ia = 0; ia < atoms.size(); ia++) { ft.real_value += atoms[ia].grad * atoms[ia].system_force; } ft.real_value *= atoms.size(); } void colvar::rmsd::calc_Jacobian_derivative() { // divergence of the rotated coordinates (including only derivatives of the rotation matrix) cvm::real divergence = 0.0; if (atoms.b_rotate) { // gradient of the rotation matrix - cvm::matrix2d grad_rot_mat; + cvm::matrix2d grad_rot_mat(3, 3); // gradients of products of 2 quaternion components cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23; for (size_t ia = 0; ia < atoms.size(); ia++) { // Gradient of optimal quaternion wrt current Cartesian position - cvm::vector1d< cvm::rvector, 4 > &dq = atoms.rot.dQ0_1[ia]; + cvm::vector1d &dq = atoms.rot.dQ0_1[ia]; g11 = 2.0 * (atoms.rot.q)[1]*dq[1]; g22 = 2.0 * (atoms.rot.q)[2]*dq[2]; g33 = 2.0 * (atoms.rot.q)[3]*dq[3]; g01 = (atoms.rot.q)[0]*dq[1] + (atoms.rot.q)[1]*dq[0]; g02 = (atoms.rot.q)[0]*dq[2] + (atoms.rot.q)[2]*dq[0]; g03 = (atoms.rot.q)[0]*dq[3] + (atoms.rot.q)[3]*dq[0]; g12 = (atoms.rot.q)[1]*dq[2] + (atoms.rot.q)[2]*dq[1]; g13 = (atoms.rot.q)[1]*dq[3] + (atoms.rot.q)[3]*dq[1]; g23 = (atoms.rot.q)[2]*dq[3] + (atoms.rot.q)[3]*dq[2]; // Gradient of the rotation matrix wrt current Cartesian position grad_rot_mat[0][0] = -2.0 * (g22 + g33); grad_rot_mat[1][0] = 2.0 * (g12 + g03); grad_rot_mat[2][0] = 2.0 * (g13 - g02); grad_rot_mat[0][1] = 2.0 * (g12 - g03); grad_rot_mat[1][1] = -2.0 * (g11 + g33); grad_rot_mat[2][1] = 2.0 * (g01 + g23); grad_rot_mat[0][2] = 2.0 * (g02 + g13); grad_rot_mat[1][2] = 2.0 * (g23 - g01); grad_rot_mat[2][2] = -2.0 * (g11 + g22); cvm::atom_pos &y = ref_pos[ia]; for (size_t alpha = 0; alpha < 3; alpha++) { for (size_t beta = 0; beta < 3; beta++) { divergence += grad_rot_mat[beta][alpha][alpha] * y[beta]; // Note: equation was derived for inverse rotation (see colvars paper) // so here the matrix is transposed // (eq would give divergence += grad_rot_mat[alpha][beta][alpha] * y[beta];) } } } } jd.real_value = x.real_value > 0.0 ? (3.0 * atoms.size() - 4.0 - divergence) / x.real_value : 0.0; } -colvar::eigenvector::eigenvector (std::string const &conf) - : cvc (conf) +colvar::eigenvector::eigenvector(std::string const &conf) + : cvc(conf) { b_inverse_gradients = true; b_Jacobian_derivative = true; function_type = "eigenvector"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); - parse_group (conf, "atoms", atoms); - atom_groups.push_back (&atoms); + parse_group(conf, "atoms", atoms); + atom_groups.push_back(&atoms); { - bool const b_inline = get_keyval (conf, "refPositions", ref_pos, ref_pos); + bool const b_inline = get_keyval(conf, "refPositions", ref_pos, ref_pos); if (b_inline) { - cvm::log ("Using reference positions from input file.\n"); + cvm::log("Using reference positions from input file.\n"); if (ref_pos.size() != atoms.size()) { - cvm::error ("Error: reference positions do not " + cvm::error("Error: reference positions do not " "match the number of requested atoms.\n"); return; } } std::string file_name; - if (get_keyval (conf, "refPositionsFile", file_name)) { + if (get_keyval(conf, "refPositionsFile", file_name)) { if (b_inline) { - cvm::error ("Error: refPositions and refPositionsFile cannot be specified at the same time.\n"); + cvm::error("Error: refPositions and refPositionsFile cannot be specified at the same time.\n"); return; } std::string file_col; double file_col_value; - if (get_keyval (conf, "refPositionsCol", file_col, std::string (""))) { + if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) { // use PDB flags if column is provided - bool found = get_keyval (conf, "refPositionsColValue", file_col_value, 0.0); + bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0); if (found && !file_col_value) { - cvm::error ("Error: refPositionsColValue, " + cvm::error("Error: refPositionsColValue, " "if provided, must be non-zero.\n"); return; } } else { // if not, use atom indices atoms.create_sorted_ids(); } - ref_pos.resize (atoms.size()); - cvm::load_coords (file_name.c_str(), ref_pos, atoms.sorted_ids, file_col, file_col_value); + ref_pos.resize(atoms.size()); + cvm::load_coords(file_name.c_str(), ref_pos, atoms.sorted_ids, file_col, file_col_value); } } // save for later the geometric center of the provided positions (may not be the origin) - cvm::rvector ref_pos_center (0.0, 0.0, 0.0); + cvm::rvector ref_pos_center(0.0, 0.0, 0.0); for (size_t i = 0; i < atoms.size(); i++) { ref_pos_center += ref_pos[i]; } ref_pos_center *= 1.0 / atoms.size(); if (atoms.b_user_defined_fit) { - cvm::log ("WARNING: explicit fitting parameters were provided for atom group \"atoms\".\n"); + cvm::log("WARNING: explicit fitting parameters were provided for atom group \"atoms\".\n"); } else { // default: fit everything - cvm::log ("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating the vector projection: " + cvm::log("Enabling \"centerReference\" and \"rotateReference\", to minimize RMSD before calculating the vector projection: " "if this is not the desired behavior, disable them explicitly within the \"atoms\" block.\n"); atoms.b_center = true; atoms.b_rotate = true; atoms.ref_pos = ref_pos; atoms.center_ref_pos(); // request the calculation of the derivatives of the rotation defined by the atom group - atoms.rot.request_group1_gradients (atoms.size()); + 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()); + atoms.rot.request_group2_gradients(atoms.size()); } { - bool const b_inline = get_keyval (conf, "vector", eigenvec, eigenvec); + bool const b_inline = get_keyval(conf, "vector", eigenvec, eigenvec); // now load the eigenvector if (b_inline) { - cvm::log ("Using vector components from input file.\n"); + cvm::log("Using vector components from input file.\n"); if (eigenvec.size() != atoms.size()) { - cvm::fatal_error ("Error: vector components do not " + cvm::fatal_error("Error: vector components do not " "match the number of requested atoms.\n"); } } std::string file_name; - if (get_keyval (conf, "vectorFile", file_name)) { + if (get_keyval(conf, "vectorFile", file_name)) { if (b_inline) { - cvm::error ("Error: vector and vectorFile cannot be specified at the same time.\n"); + cvm::error("Error: vector and vectorFile cannot be specified at the same time.\n"); return; } std::string file_col; double file_col_value; - if (get_keyval (conf, "vectorCol", file_col, std::string (""))) { + if (get_keyval(conf, "vectorCol", file_col, std::string(""))) { // use PDB flags if column is provided - bool found = get_keyval (conf, "vectorColValue", file_col_value, 0.0); + bool found = get_keyval(conf, "vectorColValue", file_col_value, 0.0); if (found && !file_col_value) { - cvm::error ("Error: vectorColValue, if provided, must be non-zero.\n"); + cvm::error("Error: vectorColValue, if provided, must be non-zero.\n"); return; } } else { // if not, use atom indices atoms.create_sorted_ids(); } - eigenvec.resize (atoms.size()); - cvm::load_coords (file_name.c_str(), eigenvec, atoms.sorted_ids, file_col, file_col_value); + eigenvec.resize(atoms.size()); + cvm::load_coords(file_name.c_str(), eigenvec, atoms.sorted_ids, file_col, file_col_value); } } if (!ref_pos.size() || !eigenvec.size()) { - cvm::error ("Error: both reference coordinates" + cvm::error("Error: both reference coordinates" "and eigenvector must be defined.\n"); return; } - cvm::atom_pos eig_center (0.0, 0.0, 0.0); + cvm::atom_pos eig_center(0.0, 0.0, 0.0); for (size_t eil = 0; eil < atoms.size(); eil++) { eig_center += eigenvec[eil]; } eig_center *= 1.0 / atoms.size(); - cvm::log ("Geometric center of the provided vector: "+cvm::to_str (eig_center)+"\n"); + cvm::log("Geometric center of the provided vector: "+cvm::to_str(eig_center)+"\n"); bool b_difference_vector = false; - get_keyval (conf, "differenceVector", b_difference_vector, false); + get_keyval(conf, "differenceVector", b_difference_vector, false); if (b_difference_vector) { if (atoms.b_center) { // both sets should be centered on the origin for fitting for (size_t i = 0; i < atoms.size(); i++) { eigenvec[i] -= eig_center; ref_pos[i] -= ref_pos_center; } } if (atoms.b_rotate) { - atoms.rot.calc_optimal_rotation (eigenvec, ref_pos); + atoms.rot.calc_optimal_rotation(eigenvec, ref_pos); for (size_t i = 0; i < atoms.size(); i++) { - eigenvec[i] = atoms.rot.rotate (eigenvec[i]); + eigenvec[i] = atoms.rot.rotate(eigenvec[i]); } } - cvm::log ("\"differenceVector\" is on: subtracting the reference positions from the provided vector: v = v - x0.\n"); + cvm::log("\"differenceVector\" is on: subtracting the reference positions from the provided vector: v = v - x0.\n"); for (size_t i = 0; i < atoms.size(); i++) { eigenvec[i] -= ref_pos[i]; } if (atoms.b_center) { // bring back the ref positions to where they were for (size_t i = 0; i < atoms.size(); i++) { ref_pos[i] += ref_pos_center; } } } else { - cvm::log ("Centering the provided vector to zero.\n"); + cvm::log("Centering the provided vector to zero.\n"); for (size_t i = 0; i < atoms.size(); i++) { eigenvec[i] -= eig_center; } } - // cvm::log ("The first three components (v1x, v1y, v1z) of the resulting vector are: "+cvm::to_str (eigenvec[0])+".\n"); + // cvm::log("The first three components(v1x, v1y, v1z) of the resulting vector are: "+cvm::to_str (eigenvec[0])+".\n"); // for inverse gradients eigenvec_invnorm2 = 0.0; for (size_t ein = 0; ein < atoms.size(); ein++) { eigenvec_invnorm2 += eigenvec[ein].norm2(); } eigenvec_invnorm2 = 1.0 / eigenvec_invnorm2; if (b_difference_vector) { - cvm::log ("\"differenceVector\" is on: normalizing the vector.\n"); + cvm::log("\"differenceVector\" is on: normalizing the vector.\n"); for (size_t i = 0; i < atoms.size(); i++) { eigenvec[i] *= eigenvec_invnorm2; } } else { - cvm::log ("The norm of the vector is |v| = "+cvm::to_str (eigenvec_invnorm2)+".\n"); + cvm::log("The norm of the vector is |v| = "+cvm::to_str(eigenvec_invnorm2)+".\n"); } } void colvar::eigenvector::calc_value() { x.real_value = 0.0; for (size_t i = 0; i < atoms.size(); i++) { x.real_value += (atoms[i].pos - ref_pos[i]) * eigenvec[i]; } } void colvar::eigenvector::calc_gradients() { for (size_t ia = 0; ia < atoms.size(); ia++) { atoms[ia].grad = eigenvec[ia]; } if (b_debug_gradients) { - cvm::log ("Debugging gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging gradients:\n"); + debug_gradients(atoms); } } -void colvar::eigenvector::apply_force (colvarvalue const &force) +void colvar::eigenvector::apply_force(colvarvalue const &force) { if (!atoms.noforce) - atoms.apply_colvar_force (force.real_value); + atoms.apply_colvar_force(force.real_value); } void colvar::eigenvector::calc_force_invgrads() { atoms.read_system_forces(); ft.real_value = 0.0; for (size_t ia = 0; ia < atoms.size(); ia++) { ft.real_value += eigenvec_invnorm2 * atoms[ia].grad * atoms[ia].system_force; } } void colvar::eigenvector::calc_Jacobian_derivative() { // gradient of the rotation matrix - cvm::matrix2d grad_rot_mat; + cvm::matrix2d grad_rot_mat(3, 3); cvm::quaternion &quat0 = atoms.rot.q; // gradients of products of 2 quaternion components cvm::rvector g11, g22, g33, g01, g02, g03, g12, g13, g23; cvm::real sum = 0.0; for (size_t ia = 0; ia < atoms.size(); ia++) { // Gradient of optimal quaternion wrt current Cartesian position // trick: d(R^-1)/dx = d(R^t)/dx = (dR/dx)^t // we can just transpose the derivatives of the direct matrix - cvm::vector1d< cvm::rvector, 4 > &dq_1 = atoms.rot.dQ0_1[ia]; + cvm::vector1d &dq_1 = atoms.rot.dQ0_1[ia]; g11 = 2.0 * quat0[1]*dq_1[1]; g22 = 2.0 * quat0[2]*dq_1[2]; g33 = 2.0 * quat0[3]*dq_1[3]; g01 = quat0[0]*dq_1[1] + quat0[1]*dq_1[0]; g02 = quat0[0]*dq_1[2] + quat0[2]*dq_1[0]; g03 = quat0[0]*dq_1[3] + quat0[3]*dq_1[0]; g12 = quat0[1]*dq_1[2] + quat0[2]*dq_1[1]; g13 = quat0[1]*dq_1[3] + quat0[3]*dq_1[1]; g23 = quat0[2]*dq_1[3] + quat0[3]*dq_1[2]; // Gradient of the inverse rotation matrix wrt current Cartesian position // (transpose of the gradient of the direct rotation) grad_rot_mat[0][0] = -2.0 * (g22 + g33); grad_rot_mat[0][1] = 2.0 * (g12 + g03); grad_rot_mat[0][2] = 2.0 * (g13 - g02); grad_rot_mat[1][0] = 2.0 * (g12 - g03); grad_rot_mat[1][1] = -2.0 * (g11 + g33); grad_rot_mat[1][2] = 2.0 * (g01 + g23); grad_rot_mat[2][0] = 2.0 * (g02 + g13); grad_rot_mat[2][1] = 2.0 * (g23 - g01); grad_rot_mat[2][2] = -2.0 * (g11 + g22); for (size_t i = 0; i < 3; i++) { for (size_t j = 0; j < 3; j++) { sum += grad_rot_mat[i][j][i] * eigenvec[ia][j]; } } } - jd.real_value = sum * std::sqrt (eigenvec_invnorm2); + jd.real_value = sum * std::sqrt(eigenvec_invnorm2); } +colvar::cartesian::cartesian(std::string const &conf) + : cvc(conf) +{ + b_inverse_gradients = false; + b_Jacobian_derivative = false; + function_type = "cartesian"; + + parse_group(conf, "atoms", atoms); + atom_groups.push_back(&atoms); + + x.type(colvarvalue::type_vector); + x.vector1d_value.resize(atoms.size() * 3); +} +void colvar::cartesian::calc_value() +{ + int ia, j; + for (ia = 0; ia < atoms.size(); ia++) { + for (j = 0; j < 3; j++) { + x.vector1d_value[3*ia + j] = atoms[ia].pos[j]; + } + } +} + + +void colvar::cartesian::calc_gradients() +{ + // we're not using the "grad" member of each + // atom object, because it only can represent the gradient of a + // scalar colvar +} + + +void colvar::cartesian::apply_force(colvarvalue const &force) +{ + int ia, j; + if (!atoms.noforce) { + cvm::rvector f; + for (ia = 0; ia < atoms.size(); ia++) { + for (j = 0; j < 3; j++) { + f[j] = force.vector1d_value[3*ia + j]; + } + atoms[ia].apply_force(f); + } + } +} + diff --git a/lib/colvars/colvarcomp_protein.cpp b/lib/colvars/colvarcomp_protein.cpp index 5021f6059..ddd3113fc 100644 --- a/lib/colvars/colvarcomp_protein.cpp +++ b/lib/colvars/colvarcomp_protein.cpp @@ -1,388 +1,388 @@ /// -*- c++ -*- #include #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" #include "colvar.h" #include "colvarcomp.h" ////////////////////////////////////////////////////////////////////// // alpha component ////////////////////////////////////////////////////////////////////// -colvar::alpha_angles::alpha_angles (std::string const &conf) - : cvc (conf) +colvar::alpha_angles::alpha_angles(std::string const &conf) + : cvc(conf) { if (cvm::debug()) - cvm::log ("Initializing alpha_angles object.\n"); + cvm::log("Initializing alpha_angles object.\n"); function_type = "alpha_angles"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); std::string segment_id; - get_keyval (conf, "psfSegID", segment_id, std::string ("MAIN")); + get_keyval(conf, "psfSegID", segment_id, std::string("MAIN")); std::vector residues; { std::string residues_conf = ""; - key_lookup (conf, "residueRange", residues_conf); + key_lookup(conf, "residueRange", residues_conf); if (residues_conf.size()) { - std::istringstream is (residues_conf); + std::istringstream is(residues_conf); int initial, final; char dash; if ( (is >> initial) && (initial > 0) && (is >> dash) && (dash == '-') && (is >> final) && (final > 0) ) { for (int rnum = initial; rnum <= final; rnum++) { - residues.push_back (rnum); + residues.push_back(rnum); } } } else { - cvm::fatal_error ("Error: no residues defined in \"residueRange\".\n"); + cvm::fatal_error("Error: no residues defined in \"residueRange\".\n"); } } if (residues.size() < 5) { - cvm::fatal_error ("Error: not enough residues defined in \"residueRange\".\n"); + cvm::fatal_error("Error: not enough residues defined in \"residueRange\".\n"); } std::string const &sid = segment_id; std::vector const &r = residues; - get_keyval (conf, "hBondCoeff", hb_coeff, 0.5); + get_keyval(conf, "hBondCoeff", hb_coeff, 0.5); if ( (hb_coeff < 0.0) || (hb_coeff > 1.0) ) { - cvm::fatal_error ("Error: hBondCoeff must be defined between 0 and 1.\n"); + cvm::fatal_error("Error: hBondCoeff must be defined between 0 and 1.\n"); } - get_keyval (conf, "angleRef", theta_ref, 88.0); - get_keyval (conf, "angleTol", theta_tol, 15.0); + get_keyval(conf, "angleRef", theta_ref, 88.0); + get_keyval(conf, "angleTol", theta_tol, 15.0); if (hb_coeff < 1.0) { for (size_t i = 0; i < residues.size()-2; i++) { - theta.push_back (new colvar::angle (cvm::atom (r[i ], "CA", sid), - cvm::atom (r[i+1], "CA", sid), - cvm::atom (r[i+2], "CA", sid))); + theta.push_back(new colvar::angle(cvm::atom(r[i ], "CA", sid), + cvm::atom(r[i+1], "CA", sid), + cvm::atom(r[i+2], "CA", sid))); } } else { - cvm::log ("The hBondCoeff specified will disable the Calpha-Calpha-Calpha angle terms.\n"); + cvm::log("The hBondCoeff specified will disable the Calpha-Calpha-Calpha angle terms.\n"); } { cvm::real r0; size_t en, ed; - get_keyval (conf, "hBondCutoff", r0, (3.3 * cvm::unit_angstrom())); - get_keyval (conf, "hBondExpNumer", en, 6); - get_keyval (conf, "hBondExpDenom", ed, 8); + get_keyval(conf, "hBondCutoff", r0, (3.3 * cvm::unit_angstrom())); + get_keyval(conf, "hBondExpNumer", en, 6); + get_keyval(conf, "hBondExpDenom", ed, 8); if (hb_coeff > 0.0) { for (size_t i = 0; i < residues.size()-4; i++) { - hb.push_back (new colvar::h_bond (cvm::atom (r[i ], "O", sid), - cvm::atom (r[i+4], "N", sid), + hb.push_back(new colvar::h_bond(cvm::atom(r[i ], "O", sid), + cvm::atom(r[i+4], "N", sid), r0, en, ed)); } } else { - cvm::log ("The hBondCoeff specified will disable the hydrogen bond terms.\n"); + cvm::log("The hBondCoeff specified will disable the hydrogen bond terms.\n"); } } if (cvm::debug()) - cvm::log ("Done initializing alpha_angles object.\n"); + cvm::log("Done initializing alpha_angles object.\n"); } colvar::alpha_angles::alpha_angles() - : cvc () + : cvc() { function_type = "alpha_angles"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::alpha_angles::~alpha_angles() { while (theta.size() != 0) { delete theta.back(); theta.pop_back(); } while (hb.size() != 0) { delete hb.back(); hb.pop_back(); } } void colvar::alpha_angles::calc_value() { x.real_value = 0.0; if (theta.size()) { cvm::real const theta_norm = - (1.0-hb_coeff) / cvm::real (theta.size()); + (1.0-hb_coeff) / cvm::real(theta.size()); for (size_t i = 0; i < theta.size(); i++) { (theta[i])->calc_value(); cvm::real const t = ((theta[i])->value().real_value-theta_ref)/theta_tol; - cvm::real const f = ( (1.0 - std::pow (t, (int) 2)) / - (1.0 - std::pow (t, (int) 4)) ); + cvm::real const f = ( (1.0 - std::pow(t, (int) 2)) / + (1.0 - std::pow(t, (int) 4)) ); x.real_value += theta_norm * f; if (cvm::debug()) - cvm::log ("Calpha-Calpha angle no. "+cvm::to_str (i+1)+" in \""+ + cvm::log("Calpha-Calpha angle no. "+cvm::to_str(i+1)+" in \""+ this->name+"\" has a value of "+ - (cvm::to_str ((theta[i])->value().real_value))+ - " degrees, f = "+cvm::to_str (f)+".\n"); + (cvm::to_str((theta[i])->value().real_value))+ + " degrees, f = "+cvm::to_str(f)+".\n"); } } if (hb.size()) { cvm::real const hb_norm = - hb_coeff / cvm::real (hb.size()); + hb_coeff / cvm::real(hb.size()); for (size_t i = 0; i < hb.size(); i++) { (hb[i])->calc_value(); x.real_value += hb_norm * (hb[i])->value().real_value; if (cvm::debug()) - cvm::log ("Hydrogen bond no. "+cvm::to_str (i+1)+" in \""+ + cvm::log("Hydrogen bond no. "+cvm::to_str(i+1)+" in \""+ this->name+"\" has a value of "+ - (cvm::to_str ((hb[i])->value().real_value))+".\n"); + (cvm::to_str((hb[i])->value().real_value))+".\n"); } } } void colvar::alpha_angles::calc_gradients() { size_t i; for (i = 0; i < theta.size(); i++) (theta[i])->calc_gradients(); for (i = 0; i < hb.size(); i++) (hb[i])->calc_gradients(); } -void colvar::alpha_angles::apply_force (colvarvalue const &force) +void colvar::alpha_angles::apply_force(colvarvalue const &force) { if (theta.size()) { cvm::real const theta_norm = - (1.0-hb_coeff) / cvm::real (theta.size()); + (1.0-hb_coeff) / cvm::real(theta.size()); for (size_t i = 0; i < theta.size(); i++) { cvm::real const t = ((theta[i])->value().real_value-theta_ref)/theta_tol; - cvm::real const f = ( (1.0 - std::pow (t, (int) 2)) / - (1.0 - std::pow (t, (int) 4)) ); + cvm::real const f = ( (1.0 - std::pow(t, (int) 2)) / + (1.0 - std::pow(t, (int) 4)) ); cvm::real const dfdt = - 1.0/(1.0 - std::pow (t, (int) 4)) * - ( (-2.0 * t) + (-1.0*f)*(-4.0 * std::pow (t, (int) 3)) ); + 1.0/(1.0 - std::pow(t, (int) 4)) * + ( (-2.0 * t) + (-1.0*f)*(-4.0 * std::pow(t, (int) 3)) ); - (theta[i])->apply_force (theta_norm * + (theta[i])->apply_force(theta_norm * dfdt * (1.0/theta_tol) * force.real_value ); } } if (hb.size()) { cvm::real const hb_norm = - hb_coeff / cvm::real (hb.size()); + hb_coeff / cvm::real(hb.size()); for (size_t i = 0; i < hb.size(); i++) { - (hb[i])->apply_force (0.5 * hb_norm * force.real_value); + (hb[i])->apply_force(0.5 * hb_norm * force.real_value); } } } ////////////////////////////////////////////////////////////////////// // dihedral principal component ////////////////////////////////////////////////////////////////////// // FIXME: this will not make collect_gradients work // because gradients in individual atom groups // are those of the sub-cvcs (angle, hb), not those // of this cvc (alpha) // This is true of all cvcs with sub-cvcs, and those // that do not calculate explicit gradients // SO: we need a flag giving the availability of // atomic gradients -colvar::dihedPC::dihedPC (std::string const &conf) - : cvc (conf) +colvar::dihedPC::dihedPC(std::string const &conf) + : cvc(conf) { if (cvm::debug()) - cvm::log ("Initializing dihedral PC object.\n"); + cvm::log("Initializing dihedral PC object.\n"); function_type = "dihedPC"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); std::string segment_id; - get_keyval (conf, "psfSegID", segment_id, std::string ("MAIN")); + get_keyval(conf, "psfSegID", segment_id, std::string("MAIN")); std::vector residues; { std::string residues_conf = ""; - key_lookup (conf, "residueRange", residues_conf); + key_lookup(conf, "residueRange", residues_conf); if (residues_conf.size()) { - std::istringstream is (residues_conf); + std::istringstream is(residues_conf); int initial, final; char dash; if ( (is >> initial) && (initial > 0) && (is >> dash) && (dash == '-') && (is >> final) && (final > 0) ) { for (int rnum = initial; rnum <= final; rnum++) { - residues.push_back (rnum); + residues.push_back(rnum); } } } else { - cvm::fatal_error ("Error: no residues defined in \"residueRange\".\n"); + cvm::fatal_error("Error: no residues defined in \"residueRange\".\n"); } } if (residues.size() < 2) { - cvm::fatal_error ("Error: dihedralPC requires at least two residues.\n"); + cvm::fatal_error("Error: dihedralPC requires at least two residues.\n"); } std::string const &sid = segment_id; std::vector const &r = residues; std::string vecFileName; int vecNumber; - if (get_keyval (conf, "vectorFile", vecFileName, vecFileName)) { - get_keyval (conf, "vectorNumber", vecNumber, 0); + if (get_keyval(conf, "vectorFile", vecFileName, vecFileName)) { + get_keyval(conf, "vectorNumber", vecNumber, 0); if (vecNumber < 1) - cvm::fatal_error ("A positive value of vectorNumber is required."); + cvm::fatal_error("A positive value of vectorNumber is required."); std::ifstream vecFile; - vecFile.open (vecFileName.c_str()); + vecFile.open(vecFileName.c_str()); if (!vecFile.good()) - cvm::fatal_error ("Error opening dihedral PCA vector file " + vecFileName + " for reading"); + cvm::fatal_error("Error opening dihedral PCA vector file " + vecFileName + " for reading"); // TODO: adapt to different formats by setting this flag bool eigenvectors_as_columns = true; if (eigenvectors_as_columns) { // Carma-style dPCA file std::string line; cvm::real c; while (vecFile.good()) { getline(vecFile, line); if (line.length() < 2) break; - std::istringstream ls (line); + std::istringstream ls(line); for (int i=0; i> c; coeffs.push_back(c); } } /* TODO Uncomment this when different formats are recognized else { // Eigenvectors as lines // Skip to the right line for (int i = 1; i> c; coeffs.push_back(c); } } */ vecFile.close(); } else { - get_keyval (conf, "vector", coeffs, coeffs); + get_keyval(conf, "vector", coeffs, coeffs); } if ( coeffs.size() != 4 * (residues.size() - 1)) { - cvm::fatal_error ("Error: wrong number of coefficients: " + + cvm::fatal_error("Error: wrong number of coefficients: " + cvm::to_str(coeffs.size()) + ". Expected " + cvm::to_str(4 * (residues.size() - 1)) + " (4 coeffs per residue, minus one residue).\n"); } for (size_t i = 0; i < residues.size()-1; i++) { // Psi - theta.push_back (new colvar::dihedral (cvm::atom (r[i ], "N", sid), - cvm::atom (r[i ], "CA", sid), - cvm::atom (r[i ], "C", sid), - cvm::atom (r[i+1], "N", sid))); + theta.push_back(new colvar::dihedral(cvm::atom(r[i ], "N", sid), + cvm::atom(r[i ], "CA", sid), + cvm::atom(r[i ], "C", sid), + cvm::atom(r[i+1], "N", sid))); // Phi (next res) - theta.push_back (new colvar::dihedral (cvm::atom (r[i ], "C", sid), - cvm::atom (r[i+1], "N", sid), - cvm::atom (r[i+1], "CA", sid), - cvm::atom (r[i+1], "C", sid))); + theta.push_back(new colvar::dihedral(cvm::atom(r[i ], "C", sid), + cvm::atom(r[i+1], "N", sid), + cvm::atom(r[i+1], "CA", sid), + cvm::atom(r[i+1], "C", sid))); } if (cvm::debug()) - cvm::log ("Done initializing dihedPC object.\n"); + cvm::log("Done initializing dihedPC object.\n"); } colvar::dihedPC::dihedPC() - : cvc () + : cvc() { function_type = "dihedPC"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::dihedPC::~dihedPC() { while (theta.size() != 0) { delete theta.back(); theta.pop_back(); } } void colvar::dihedPC::calc_value() { x.real_value = 0.0; for (size_t i = 0; i < theta.size(); i++) { theta[i]->calc_value(); cvm::real const t = (PI / 180.) * theta[i]->value().real_value; x.real_value += coeffs[2*i ] * std::cos(t) + coeffs[2*i+1] * std::sin(t); } } void colvar::dihedPC::calc_gradients() { for (size_t i = 0; i < theta.size(); i++) { theta[i]->calc_gradients(); } } -void colvar::dihedPC::apply_force (colvarvalue const &force) +void colvar::dihedPC::apply_force(colvarvalue const &force) { for (size_t i = 0; i < theta.size(); i++) { cvm::real const t = (PI / 180.) * theta[i]->value().real_value; cvm::real const dcosdt = - (PI / 180.) * std::sin(t); cvm::real const dsindt = (PI / 180.) * std::cos(t); theta[i]->apply_force((coeffs[2*i ] * dcosdt + coeffs[2*i+1] * dsindt) * force); } } diff --git a/lib/colvars/colvarcomp_rotations.cpp b/lib/colvars/colvarcomp_rotations.cpp index 0c52b989b..a4c5f2187 100644 --- a/lib/colvars/colvarcomp_rotations.cpp +++ b/lib/colvars/colvarcomp_rotations.cpp @@ -1,366 +1,366 @@ /// -*- c++ -*- #include #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" #include "colvar.h" #include "colvarcomp.h" -colvar::orientation::orientation (std::string const &conf) - : cvc (conf) +colvar::orientation::orientation(std::string const &conf) + : cvc(conf) { function_type = "orientation"; - parse_group (conf, "atoms", atoms); - atom_groups.push_back (&atoms); - x.type (colvarvalue::type_quaternion); + parse_group(conf, "atoms", atoms); + atom_groups.push_back(&atoms); + x.type(colvarvalue::type_quaternion); - ref_pos.reserve (atoms.size()); + ref_pos.reserve(atoms.size()); - if (get_keyval (conf, "refPositions", ref_pos, ref_pos)) { - cvm::log ("Using reference positions from input file.\n"); + if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) { + cvm::log("Using reference positions from input file.\n"); if (ref_pos.size() != atoms.size()) { - cvm::fatal_error ("Error: reference positions do not " + cvm::fatal_error("Error: reference positions do not " "match the number of requested atoms.\n"); } } { std::string file_name; - if (get_keyval (conf, "refPositionsFile", file_name)) { + if (get_keyval(conf, "refPositionsFile", file_name)) { std::string file_col; double file_col_value; - if (get_keyval (conf, "refPositionsCol", file_col, std::string (""))) { + if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) { // use PDB flags if column is provided - bool found = get_keyval (conf, "refPositionsColValue", file_col_value, 0.0); + bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0); if (found && !file_col_value) - cvm::fatal_error ("Error: refPositionsColValue, " + cvm::fatal_error("Error: refPositionsColValue, " "if provided, must be non-zero.\n"); } else { // if not, use atom indices atoms.create_sorted_ids(); } - ref_pos.resize (atoms.size()); - cvm::load_coords (file_name.c_str(), ref_pos, atoms.sorted_ids, file_col, file_col_value); + ref_pos.resize(atoms.size()); + cvm::load_coords(file_name.c_str(), ref_pos, atoms.sorted_ids, file_col, file_col_value); } } if (!ref_pos.size()) { - cvm::fatal_error ("Error: must define a set of " + cvm::fatal_error("Error: must define a set of " "reference coordinates.\n"); } - cvm::log ("Centering the reference coordinates: it is " + cvm::log("Centering the reference coordinates: it is " "assumed that each atom is the closest " "periodic image to the center of geometry.\n"); - cvm::rvector cog (0.0, 0.0, 0.0); + cvm::rvector cog(0.0, 0.0, 0.0); size_t i; for (i = 0; i < ref_pos.size(); i++) { cog += ref_pos[i]; } - cog /= cvm::real (ref_pos.size()); + cog /= cvm::real(ref_pos.size()); for (i = 0; i < ref_pos.size(); i++) { ref_pos[i] -= cog; } - get_keyval (conf, "closestToQuaternion", ref_quat, cvm::quaternion (1.0, 0.0, 0.0, 0.0)); + get_keyval(conf, "closestToQuaternion", ref_quat, cvm::quaternion(1.0, 0.0, 0.0, 0.0)); // initialize rot member data if (!atoms.noforce) { - rot.request_group2_gradients (atoms.size()); + rot.request_group2_gradients(atoms.size()); } } colvar::orientation::orientation() - : cvc () + : cvc() { function_type = "orientation"; - x.type (colvarvalue::type_quaternion); + x.type(colvarvalue::type_quaternion); } void colvar::orientation::calc_value() { // atoms.reset_atoms_data(); // atoms.read_positions(); atoms_cog = atoms.center_of_geometry(); - rot.calc_optimal_rotation (ref_pos, atoms.positions_shifted (-1.0 * atoms_cog)); + rot.calc_optimal_rotation(ref_pos, atoms.positions_shifted(-1.0 * atoms_cog)); - if ((rot.q).inner (ref_quat) >= 0.0) { + if ((rot.q).inner(ref_quat) >= 0.0) { x.quaternion_value = rot.q; } else { x.quaternion_value = -1.0 * rot.q; } } void colvar::orientation::calc_gradients() { // gradients have already been calculated and stored within the // member object "rot"; we're not using the "grad" member of each // atom object, because it only can represent the gradient of a // scalar colvar } -void colvar::orientation::apply_force (colvarvalue const &force) +void colvar::orientation::apply_force(colvarvalue const &force) { cvm::quaternion const &FQ = force.quaternion_value; if (!atoms.noforce) { for (size_t ia = 0; ia < atoms.size(); ia++) { for (size_t i = 0; i < 4; i++) { - atoms[ia].apply_force (FQ[i] * rot.dQ0_2[ia][i]); + atoms[ia].apply_force(FQ[i] * rot.dQ0_2[ia][i]); } } } } -colvar::orientation_angle::orientation_angle (std::string const &conf) - : orientation (conf) +colvar::orientation_angle::orientation_angle(std::string const &conf) + : orientation(conf) { function_type = "orientation_angle"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::orientation_angle::orientation_angle() : orientation() { function_type = "orientation_angle"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::orientation_angle::calc_value() { // atoms.reset_atoms_data(); // atoms.read_positions(); atoms_cog = atoms.center_of_geometry(); - rot.calc_optimal_rotation (ref_pos, atoms.positions_shifted (-1.0 * atoms_cog)); + rot.calc_optimal_rotation(ref_pos, atoms.positions_shifted(-1.0 * atoms_cog)); if ((rot.q).q0 >= 0.0) { - x.real_value = (180.0/PI) * 2.0 * std::acos ((rot.q).q0); + x.real_value = (180.0/PI) * 2.0 * std::acos((rot.q).q0); } else { - x.real_value = (180.0/PI) * 2.0 * std::acos (-1.0 * (rot.q).q0); + x.real_value = (180.0/PI) * 2.0 * std::acos(-1.0 * (rot.q).q0); } } void colvar::orientation_angle::calc_gradients() { cvm::real const dxdq0 = ( ((rot.q).q0 * (rot.q).q0 < 1.0) ? - ((180.0 / PI) * (-2.0) / std::sqrt (1.0 - ((rot.q).q0 * (rot.q).q0))) : + ((180.0 / PI) * (-2.0) / std::sqrt(1.0 - ((rot.q).q0 * (rot.q).q0))) : 0.0 ); for (size_t ia = 0; ia < atoms.size(); ia++) { atoms[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]); } if (b_debug_gradients) { - cvm::log ("Debugging orientationAngle component gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging orientationAngle component gradients:\n"); + debug_gradients(atoms); } } -void colvar::orientation_angle::apply_force (colvarvalue const &force) +void colvar::orientation_angle::apply_force(colvarvalue const &force) { cvm::real const &fw = force.real_value; if (!atoms.noforce) { - atoms.apply_colvar_force (fw); + atoms.apply_colvar_force(fw); } } -colvar::orientation_proj::orientation_proj (std::string const &conf) - : orientation (conf) +colvar::orientation_proj::orientation_proj(std::string const &conf) + : orientation(conf) { function_type = "orientation_proj"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::orientation_proj::orientation_proj() : orientation() { function_type = "orientation_proj"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::orientation_proj::calc_value() { atoms_cog = atoms.center_of_geometry(); - rot.calc_optimal_rotation (ref_pos, atoms.positions_shifted (-1.0 * atoms_cog)); + rot.calc_optimal_rotation(ref_pos, atoms.positions_shifted(-1.0 * atoms_cog)); x.real_value = 2.0 * (rot.q).q0 * (rot.q).q0 - 1.0; } void colvar::orientation_proj::calc_gradients() { cvm::real const dxdq0 = 2.0 * 2.0 * (rot.q).q0; for (size_t ia = 0; ia < atoms.size(); ia++) { atoms[ia].grad = (dxdq0 * (rot.dQ0_2[ia])[0]); } if (b_debug_gradients) { - cvm::log ("Debugging orientationProj component gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging orientationProj component gradients:\n"); + debug_gradients(atoms); } } -void colvar::orientation_proj::apply_force (colvarvalue const &force) +void colvar::orientation_proj::apply_force(colvarvalue const &force) { cvm::real const &fw = force.real_value; if (!atoms.noforce) { - atoms.apply_colvar_force (fw); + atoms.apply_colvar_force(fw); } } -colvar::tilt::tilt (std::string const &conf) - : orientation (conf) +colvar::tilt::tilt(std::string const &conf) + : orientation(conf) { function_type = "tilt"; - get_keyval (conf, "axis", axis, cvm::rvector (0.0, 0.0, 1.0)); + get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0)); if (axis.norm2() != 1.0) { axis /= axis.norm(); - cvm::log ("Normalizing rotation axis to "+cvm::to_str (axis)+".\n"); + cvm::log("Normalizing rotation axis to "+cvm::to_str(axis)+".\n"); } - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::tilt::tilt() : orientation() { function_type = "tilt"; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::tilt::calc_value() { // atoms.reset_atoms_data(); // atoms.read_positions(); atoms_cog = atoms.center_of_geometry(); - rot.calc_optimal_rotation (ref_pos, atoms.positions_shifted (-1.0 * atoms_cog)); + rot.calc_optimal_rotation(ref_pos, atoms.positions_shifted(-1.0 * atoms_cog)); - x.real_value = rot.cos_theta (axis); + x.real_value = rot.cos_theta(axis); } void colvar::tilt::calc_gradients() { - cvm::quaternion const dxdq = rot.dcos_theta_dq (axis); + cvm::quaternion const dxdq = rot.dcos_theta_dq(axis); for (size_t ia = 0; ia < atoms.size(); ia++) { - atoms[ia].grad = cvm::rvector (0.0, 0.0, 0.0); + atoms[ia].grad = cvm::rvector(0.0, 0.0, 0.0); for (size_t iq = 0; iq < 4; iq++) { atoms[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]); } } if (b_debug_gradients) { - cvm::log ("Debugging tilt component gradients:\n"); - debug_gradients (atoms); + cvm::log("Debugging tilt component gradients:\n"); + debug_gradients(atoms); } } -void colvar::tilt::apply_force (colvarvalue const &force) +void colvar::tilt::apply_force(colvarvalue const &force) { cvm::real const &fw = force.real_value; if (!atoms.noforce) { - atoms.apply_colvar_force (fw); + atoms.apply_colvar_force(fw); } } -colvar::spin_angle::spin_angle (std::string const &conf) - : orientation (conf) +colvar::spin_angle::spin_angle(std::string const &conf) + : orientation(conf) { function_type = "spin_angle"; - get_keyval (conf, "axis", axis, cvm::rvector (0.0, 0.0, 1.0)); + get_keyval(conf, "axis", axis, cvm::rvector(0.0, 0.0, 1.0)); if (axis.norm2() != 1.0) { axis /= axis.norm(); - cvm::log ("Normalizing rotation axis to "+cvm::to_str (axis)+".\n"); + cvm::log("Normalizing rotation axis to "+cvm::to_str(axis)+".\n"); } period = 360.0; b_periodic = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } colvar::spin_angle::spin_angle() : orientation() { function_type = "spin_angle"; period = 360.0; b_periodic = true; - x.type (colvarvalue::type_scalar); + x.type(colvarvalue::type_scalar); } void colvar::spin_angle::calc_value() { // atoms.reset_atoms_data(); // atoms.read_positions(); atoms_cog = atoms.center_of_geometry(); - rot.calc_optimal_rotation (ref_pos, atoms.positions_shifted (-1.0 * atoms_cog)); + rot.calc_optimal_rotation(ref_pos, atoms.positions_shifted(-1.0 * atoms_cog)); - x.real_value = rot.spin_angle (axis); - this->wrap (x); + x.real_value = rot.spin_angle(axis); + this->wrap(x); } void colvar::spin_angle::calc_gradients() { - cvm::quaternion const dxdq = rot.dspin_angle_dq (axis); + cvm::quaternion const dxdq = rot.dspin_angle_dq(axis); for (size_t ia = 0; ia < atoms.size(); ia++) { - atoms[ia].grad = cvm::rvector (0.0, 0.0, 0.0); + atoms[ia].grad = cvm::rvector(0.0, 0.0, 0.0); for (size_t iq = 0; iq < 4; iq++) { atoms[ia].grad += (dxdq[iq] * (rot.dQ0_2[ia])[iq]); } } } -void colvar::spin_angle::apply_force (colvarvalue const &force) +void colvar::spin_angle::apply_force(colvarvalue const &force) { cvm::real const &fw = force.real_value; if (!atoms.noforce) { - atoms.apply_colvar_force (fw); + atoms.apply_colvar_force(fw); } } diff --git a/lib/colvars/colvargrid.cpp b/lib/colvars/colvargrid.cpp index 1035cc5ac..4c2c3965e 100644 --- a/lib/colvars/colvargrid.cpp +++ b/lib/colvars/colvargrid.cpp @@ -1,217 +1,195 @@ /// -*- c++ -*- #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" #include "colvar.h" #include "colvarcomp.h" #include "colvargrid.h" colvar_grid_count::colvar_grid_count() : colvar_grid() {} -colvar_grid_count::colvar_grid_count (std::vector const &nx_i, - size_t const &def_count) - : colvar_grid (nx_i, def_count) +colvar_grid_count::colvar_grid_count(std::vector const &nx_i, + size_t const &def_count) + : colvar_grid(nx_i, def_count) {} -colvar_grid_count::colvar_grid_count (std::vector &colvars, - size_t const &def_count) - : colvar_grid (colvars, def_count) +colvar_grid_count::colvar_grid_count(std::vector &colvars, + size_t const &def_count) + : colvar_grid(colvars, def_count) {} -std::istream & colvar_grid_count::read_restart (std::istream &is) +std::istream & colvar_grid_count::read_restart(std::istream &is) { size_t const start_pos = is.tellg(); std::string key, conf; - if ((is >> key) && (key == std::string ("grid_parameters"))) { - is.seekg (start_pos, std::ios::beg); - is >> colvarparse::read_block ("grid_parameters", conf); - parse_params (conf); + if ((is >> key) && (key == std::string("grid_parameters"))) { + is.seekg(start_pos, std::ios::beg); + is >> colvarparse::read_block("grid_parameters", conf); + parse_params(conf); } else { - cvm::log ("Grid parameters are missing in the restart file, using those from the configuration.\n"); - is.seekg (start_pos, std::ios::beg); + cvm::log("Grid parameters are missing in the restart file, using those from the configuration.\n"); + is.seekg(start_pos, std::ios::beg); } - read_raw (is); + read_raw(is); return is; } -std::ostream & colvar_grid_count::write_restart (std::ostream &os) +std::ostream & colvar_grid_count::write_restart(std::ostream &os) { - write_params (os); - write_raw (os); + write_params(os); + write_raw(os); return os; } colvar_grid_scalar::colvar_grid_scalar() - : colvar_grid(), samples (NULL), grad (NULL) + : colvar_grid(), samples(NULL), grad(NULL) {} -colvar_grid_scalar::colvar_grid_scalar (colvar_grid_scalar const &g) - : colvar_grid (g), samples (NULL), grad (NULL) +colvar_grid_scalar::colvar_grid_scalar(colvar_grid_scalar const &g) + : colvar_grid(g), samples(NULL), grad(NULL) { grad = new cvm::real[nd]; } -colvar_grid_scalar::colvar_grid_scalar (std::vector const &nx_i) - : colvar_grid (nx_i, 0.0, 1), samples (NULL) +colvar_grid_scalar::colvar_grid_scalar(std::vector const &nx_i) + : colvar_grid(nx_i, 0.0, 1), samples(NULL) { grad = new cvm::real[nd]; } -colvar_grid_scalar::colvar_grid_scalar (std::vector &colvars, bool margin) - : colvar_grid (colvars, 0.0, 1, margin), samples (NULL) +colvar_grid_scalar::colvar_grid_scalar(std::vector &colvars, bool margin) + : colvar_grid(colvars, 0.0, 1, margin), samples(NULL) { grad = new cvm::real[nd]; } colvar_grid_scalar::~colvar_grid_scalar() { if (grad) { delete [] grad; grad = NULL; } } -std::istream & colvar_grid_scalar::read_restart (std::istream &is) +std::istream & colvar_grid_scalar::read_restart(std::istream &is) { size_t const start_pos = is.tellg(); std::string key, conf; - if ((is >> key) && (key == std::string ("grid_parameters"))) { - is.seekg (start_pos, std::ios::beg); - is >> colvarparse::read_block ("grid_parameters", conf); - parse_params (conf); + if ((is >> key) && (key == std::string("grid_parameters"))) { + is.seekg(start_pos, std::ios::beg); + is >> colvarparse::read_block("grid_parameters", conf); + parse_params(conf); } else { - cvm::log ("Grid parameters are missing in the restart file, using those from the configuration.\n"); - is.seekg (start_pos, std::ios::beg); + cvm::log("Grid parameters are missing in the restart file, using those from the configuration.\n"); + is.seekg(start_pos, std::ios::beg); } - read_raw (is); + read_raw(is); return is; } -std::ostream & colvar_grid_scalar::write_restart (std::ostream &os) +std::ostream & colvar_grid_scalar::write_restart(std::ostream &os) { - write_params (os); - write_raw (os); + write_params(os); + write_raw(os); return os; } colvar_grid_gradient::colvar_grid_gradient() - : colvar_grid(), samples (NULL) + : colvar_grid(), samples(NULL) {} -colvar_grid_gradient::colvar_grid_gradient (std::vector const &nx_i) - : colvar_grid (nx_i, 0.0, nx_i.size()), samples (NULL) +colvar_grid_gradient::colvar_grid_gradient(std::vector const &nx_i) + : colvar_grid(nx_i, 0.0, nx_i.size()), samples(NULL) {} -colvar_grid_gradient::colvar_grid_gradient (std::vector &colvars) - : colvar_grid (colvars, 0.0, colvars.size()), samples (NULL) +colvar_grid_gradient::colvar_grid_gradient(std::vector &colvars) + : colvar_grid(colvars, 0.0, colvars.size()), samples(NULL) {} -std::istream & colvar_grid_gradient::read_restart (std::istream &is) +std::istream & colvar_grid_gradient::read_restart(std::istream &is) { size_t const start_pos = is.tellg(); std::string key, conf; - if ((is >> key) && (key == std::string ("grid_parameters"))) { - is.seekg (start_pos, std::ios::beg); - is >> colvarparse::read_block ("grid_parameters", conf); - parse_params (conf); + if ((is >> key) && (key == std::string("grid_parameters"))) { + is.seekg(start_pos, std::ios::beg); + is >> colvarparse::read_block("grid_parameters", conf); + parse_params(conf); } else { - cvm::log ("Grid parameters are missing in the restart file, using those from the configuration.\n"); - is.seekg (start_pos, std::ios::beg); + cvm::log("Grid parameters are missing in the restart file, using those from the configuration.\n"); + is.seekg(start_pos, std::ios::beg); } - read_raw (is); + read_raw(is); return is; } -std::ostream & colvar_grid_gradient::write_restart (std::ostream &os) +std::ostream & colvar_grid_gradient::write_restart(std::ostream &os) { - write_params (os); - write_raw (os); + write_params(os); + write_raw(os); return os; } -void colvar_grid_gradient::write_1D_integral (std::ostream &os) +void colvar_grid_gradient::write_1D_integral(std::ostream &os) { cvm::real bin, min, integral; std::vector int_vals; os << "# xi A(xi)\n"; if ( cv.size() != 1 ) { - cvm::fatal_error ("Cannot write integral for multi-dimensional gradient grids."); + cvm::fatal_error("Cannot write integral for multi-dimensional gradient grids."); } integral = 0.0; - int_vals.push_back ( 0.0 ); + int_vals.push_back( 0.0 ); bin = 0.0; min = 0.0; // correction for periodic colvars, so that the PMF is periodic cvm::real corr; if ( periodic[0] ) { corr = average(); } else { corr = 0.0; } - for (std::vector ix = new_index(); index_ok (ix); incr (ix), bin += 1.0 ) { + for (std::vector ix = new_index(); index_ok(ix); incr(ix), bin += 1.0 ) { if (samples) { - size_t const samples_here = samples->value (ix); + size_t const samples_here = samples->value(ix); if (samples_here) - integral += (value (ix) / cvm::real (samples_here) - corr) * cv[0]->width; + integral += (value(ix) / cvm::real(samples_here) - corr) * cv[0]->width; } else { - integral += (value (ix) - corr) * cv[0]->width; + integral += (value(ix) - corr) * cv[0]->width; } if ( integral < min ) min = integral; - int_vals.push_back ( integral ); + int_vals.push_back( integral ); } bin = 0.0; for ( int i = 0; i < nx[0]; i++, bin += 1.0 ) { - os << std::setw (10) << cv[0]->lower_boundary.real_value + cv[0]->width * bin << " " - << std::setw (cvm::cv_width) - << std::setprecision (cvm::cv_prec) + os << std::setw(10) << cv[0]->lower_boundary.real_value + cv[0]->width * bin << " " + << std::setw(cvm::cv_width) + << std::setprecision(cvm::cv_prec) << int_vals[i] - min << "\n"; } - os << std::setw (10) << cv[0]->lower_boundary.real_value + cv[0]->width * bin << " " - << std::setw (cvm::cv_width) - << std::setprecision (cvm::cv_prec) + os << std::setw(10) << cv[0]->lower_boundary.real_value + cv[0]->width * bin << " " + << std::setw(cvm::cv_width) + << std::setprecision(cvm::cv_prec) << int_vals[nx[0]] - min << "\n"; return; } - -// quaternion_grid::quaternion_grid (std::vector const &cv_i, -// std::vector const &grid_str) -// { -// cv = cv_i; - -// std::istringstream is (grid_str[0]); -// is >> grid_size; - -// min.assign (3, -1.0); -// max.assign (3, 1.0); -// np.assign (3, grid_size); -// dx.assign (3, 2.0/(cvm::real (grid_size))); - -// // assumes a uniform grid in the three directions; change -// // get_value() if you want to use different sizes -// cvm::log ("Allocating quaternion grid ("+cvm::to_str (np.size())+" dimensional)..."); -// data.create (np, 0.0); -// cvm::log ("done.\n"); -// if (cvm::debug()) cvm::log ("Grid size = "+data.size()); -// } - diff --git a/lib/colvars/colvargrid.h b/lib/colvars/colvargrid.h index 7cc255ee7..17ff6a4fb 100644 --- a/lib/colvars/colvargrid.h +++ b/lib/colvars/colvargrid.h @@ -1,1274 +1,1274 @@ /// -*- c++ -*- #ifndef COLVARGRID_H #define COLVARGRID_H #include #include #include #include "colvar.h" #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" /// \brief Grid of values of a function of several collective /// variables \param T The data type /// /// Only scalar colvars supported so far template class colvar_grid : public colvarparse { protected: /// Number of dimensions size_t nd; /// Number of points along each dimension std::vector nx; /// Cumulative number of points along each dimension std::vector nxc; /// \brief Multiplicity of each datum (allow the binning of - /// non-scalar types) + /// non-scalar types such as atomic gradients) size_t mult; /// Total number of grid points size_t nt; /// Low-level array of values std::vector data; /// Newly read data (used for count grids, when adding several grids read from disk) std::vector new_data; /// Colvars collected in this grid std::vector cv; /// Do we request actual value (for extended-system colvars)? std::vector actual_value; /// Get the low-level index corresponding to an index - inline size_t address (std::vector const &ix) const + inline size_t address(std::vector const &ix) const { size_t addr = 0; for (size_t i = 0; i < nd; i++) { addr += ix[i]*nxc[i]; if (cvm::debug()) { if (ix[i] >= nx[i]) { - cvm::error ("Error: exceeding bounds in colvar_grid.\n"); + cvm::error("Error: exceeding bounds in colvar_grid.\n"); return 0; } } } return addr; } public: /// Lower boundaries of the colvars in this grid std::vector lower_boundaries; /// Upper boundaries of the colvars in this grid std::vector upper_boundaries; /// Whether some colvars are periodic std::vector periodic; /// Whether some colvars have hard lower boundaries std::vector hard_lower_boundaries; /// Whether some colvars have hard upper boundaries std::vector hard_upper_boundaries; /// Widths of the colvars in this grid std::vector widths; /// True if this is a count grid related to another grid of data bool has_parent_data; /// Whether this grid has been filled with data or is still empty bool has_data; /// Return the number of colvars inline size_t number_of_colvars() const { return nd; } /// Return the number of points in the i-th direction, if provided, or /// the total number - inline size_t number_of_points (int const icv = -1) const + inline size_t number_of_points(int const icv = -1) const { if (icv < 0) { return nt; } else { return nx[icv]; } } /// Get the sizes in each direction inline std::vector const & sizes() const { return nx; } /// Set the sizes in each direction - inline void set_sizes (std::vector const &new_sizes) + inline void set_sizes(std::vector const &new_sizes) { nx = new_sizes; } /// Return the multiplicity of the type used inline size_t multiplicity() const { return mult; } /// \brief Allocate data (allow initialization also after construction) - void create (std::vector const &nx_i, + void create(std::vector const &nx_i, T const &t = T(), size_t const &mult_i = 1) { mult = mult_i; nd = nx_i.size(); - nxc.resize (nd); + nxc.resize(nd); nx = nx_i; nt = mult; for (int i = nd-1; i >= 0; i--) { if (nx_i[i] <= 0) { - cvm::error ("Error: providing an invalid number of points, "+ - cvm::to_str (nx_i[i])+".\n"); + cvm::error("Error: providing an invalid number of points, "+ + cvm::to_str(nx_i[i])+".\n"); return; } nxc[i] = nt; nt *= nx[i]; } - data.reserve (nt); - data.assign (nt, t); + data.reserve(nt); + data.assign(nt, t); } /// \brief Allocate data (allow initialization also after construction) void create() { - create (this->nx, T(), this->mult); + create(this->nx, T(), this->mult); } /// \brief Reset data (in case the grid is being reused) - void reset (T const &t = T()) + void reset(T const &t = T()) { - data.assign (nt, t); + data.assign(nt, t); } /// Default constructor - colvar_grid() : has_data (false) + colvar_grid() : has_data(false) { save_delimiters = false; nd = nt = 0; } /// Destructor virtual ~colvar_grid() {} /// \brief "Almost copy-constructor": only copies configuration /// parameters from another grid, but doesn't reallocate stuff; /// create() must be called after that; - colvar_grid (colvar_grid const &g) : nd (g.nd), - nx (g.nx), - mult (g.mult), + colvar_grid(colvar_grid const &g) : nd(g.nd), + nx(g.nx), + mult(g.mult), data(), - cv (g.cv), - actual_value (g.actual_value), - lower_boundaries (g.lower_boundaries), - upper_boundaries (g.upper_boundaries), - periodic (g.periodic), - hard_lower_boundaries (g.hard_lower_boundaries), - hard_upper_boundaries (g.hard_upper_boundaries), - widths (g.widths), - has_data (false) + cv(g.cv), + actual_value(g.actual_value), + lower_boundaries(g.lower_boundaries), + upper_boundaries(g.upper_boundaries), + periodic(g.periodic), + hard_lower_boundaries(g.hard_lower_boundaries), + hard_upper_boundaries(g.hard_upper_boundaries), + widths(g.widths), + has_data(false) { save_delimiters = false; } /// \brief Constructor from explicit grid sizes \param nx_i Number /// of grid points along each dimension \param t Initial value for /// the function at each point (optional) \param mult_i Multiplicity /// of each value - colvar_grid (std::vector const &nx_i, + colvar_grid(std::vector const &nx_i, T const &t = T(), - size_t const &mult_i = 1) : has_data (false) + size_t const &mult_i = 1) : has_data(false) { save_delimiters = false; - this->create (nx_i, t, mult_i); + this->create(nx_i, t, mult_i); } /// \brief Constructor from a vector of colvars - colvar_grid (std::vector const &colvars, + colvar_grid(std::vector const &colvars, T const &t = T(), size_t const &mult_i = 1, bool margin = false) - : cv (colvars), has_data (false) + : cv(colvars), has_data(false) { save_delimiters = false; std::vector nx_i; if (cvm::debug()) - cvm::log ("Allocating a grid for "+cvm::to_str (colvars.size())+ + cvm::log("Allocating a grid for "+cvm::to_str(colvars.size())+ " collective variables.\n"); for (size_t i = 0; i < cv.size(); i++) { - if (cv[i]->type() != colvarvalue::type_scalar) { - cvm::error ("Colvar grids can only be automatically " + if (cv[i]->value().type() != colvarvalue::type_scalar) { + cvm::error("Colvar grids can only be automatically " "constructed for scalar variables. " "ABF and histogram can not be used; metadynamics " "can be used with useGrids disabled.\n"); return; } if (cv[i]->width <= 0.0) { - cvm::error ("Tried to initialize a grid on a " + cvm::error("Tried to initialize a grid on a " "variable with negative or zero width.\n"); return; } if (!cv[i]->tasks[colvar::task_lower_boundary] || !cv[i]->tasks[colvar::task_upper_boundary]) { - cvm::error ("Tried to initialize a grid on a " + cvm::error("Tried to initialize a grid on a " "variable with undefined boundaries.\n"); return; } - widths.push_back (cv[i]->width); - hard_lower_boundaries.push_back (cv[i]->hard_lower_boundary); - hard_upper_boundaries.push_back (cv[i]->hard_upper_boundary); - periodic.push_back (cv[i]->periodic_boundaries()); + widths.push_back(cv[i]->width); + hard_lower_boundaries.push_back(cv[i]->hard_lower_boundary); + hard_upper_boundaries.push_back(cv[i]->hard_upper_boundary); + periodic.push_back(cv[i]->periodic_boundaries()); // By default, get reported colvar value (for extended Lagrangian colvars) - actual_value.push_back (false); + actual_value.push_back(false); // except if a colvar is specified twice in a row // then the first instance is the actual value if (i > 0 && cv[i-1] == cv[i]) { actual_value[i-1] = true; } if (margin) { if (periodic[i]) { // Shift the grid by half the bin width (values at edges instead of center of bins) - lower_boundaries.push_back (cv[i]->lower_boundary.real_value - 0.5 * widths[i]); - upper_boundaries.push_back (cv[i]->upper_boundary.real_value - 0.5 * widths[i]); + lower_boundaries.push_back(cv[i]->lower_boundary.real_value - 0.5 * widths[i]); + upper_boundaries.push_back(cv[i]->upper_boundary.real_value - 0.5 * widths[i]); } else { // Make this grid larger by one bin width - lower_boundaries.push_back (cv[i]->lower_boundary.real_value - 0.5 * widths[i]); - upper_boundaries.push_back (cv[i]->upper_boundary.real_value + 0.5 * widths[i]); + lower_boundaries.push_back(cv[i]->lower_boundary.real_value - 0.5 * widths[i]); + upper_boundaries.push_back(cv[i]->upper_boundary.real_value + 0.5 * widths[i]); } } else { - lower_boundaries.push_back (cv[i]->lower_boundary); - upper_boundaries.push_back (cv[i]->upper_boundary); + lower_boundaries.push_back(cv[i]->lower_boundary); + upper_boundaries.push_back(cv[i]->upper_boundary); } { cvm::real nbins = ( upper_boundaries[i].real_value - lower_boundaries[i].real_value ) / widths[i]; int nbins_round = (int)(nbins+0.5); - if (std::fabs (nbins - cvm::real (nbins_round)) > 1.0E-10) { - cvm::log ("Warning: grid interval ("+ - cvm::to_str (lower_boundaries[i], cvm::cv_width, cvm::cv_prec)+" - "+ - cvm::to_str (upper_boundaries[i], cvm::cv_width, cvm::cv_prec)+ - ") is not commensurate to its bin width ("+ - cvm::to_str (widths[i], cvm::cv_width, cvm::cv_prec)+").\n"); + if (std::fabs(nbins - cvm::real(nbins_round)) > 1.0E-10) { + cvm::log("Warning: grid interval("+ + cvm::to_str(lower_boundaries[i], cvm::cv_width, cvm::cv_prec)+" - "+ + cvm::to_str(upper_boundaries[i], cvm::cv_width, cvm::cv_prec)+ + ") is not commensurate to its bin width("+ + cvm::to_str(widths[i], cvm::cv_width, cvm::cv_prec)+").\n"); upper_boundaries[i].real_value = lower_boundaries[i].real_value + (nbins_round * widths[i]); } if (cvm::debug()) - cvm::log ("Number of points is "+cvm::to_str ((int) nbins_round)+ - " for the colvar no. "+cvm::to_str (i+1)+".\n"); + cvm::log("Number of points is "+cvm::to_str((int) nbins_round)+ + " for the colvar no. "+cvm::to_str(i+1)+".\n"); - nx_i.push_back (nbins_round); + nx_i.push_back(nbins_round); } } - create (nx_i, t, mult_i); + create(nx_i, t, mult_i); } /// Wrap an index vector around periodic boundary conditions /// also checks validity of non-periodic indices - inline void wrap (std::vector & ix) const + inline void wrap(std::vector & ix) const { for (size_t i = 0; i < nd; i++) { if (periodic[i]) { ix[i] = (ix[i] + nx[i]) % nx[i]; //to ensure non-negative result } else { if (ix[i] < 0 || ix[i] >= nx[i]) - cvm::error ("Trying to wrap illegal index vector (non-PBC): " - + cvm::to_str (ix)); + cvm::error("Trying to wrap illegal index vector(non-PBC): " + + cvm::to_str(ix)); return; } } } /// \brief Report the bin corresponding to the current value of variable i inline int current_bin_scalar(int const i) const { - return value_to_bin_scalar (actual_value[i] ? cv[i]->actual_value() : cv[i]->value(), i); + return value_to_bin_scalar(actual_value[i] ? cv[i]->actual_value() : cv[i]->value(), i); } /// \brief Use the lower boundary and the width to report which bin /// the provided value is in - inline int value_to_bin_scalar (colvarvalue const &value, const int i) const + inline int value_to_bin_scalar(colvarvalue const &value, const int i) const { - return (int) std::floor ( (value.real_value - lower_boundaries[i].real_value) / widths[i] ); + return (int) std::floor( (value.real_value - lower_boundaries[i].real_value) / widths[i] ); } /// \brief Same as the standard version, but uses another grid definition - inline int value_to_bin_scalar (colvarvalue const &value, + inline int value_to_bin_scalar(colvarvalue const &value, colvarvalue const &new_offset, cvm::real const &new_width) const { - return (int) std::floor ( (value.real_value - new_offset.real_value) / new_width ); + return (int) std::floor( (value.real_value - new_offset.real_value) / new_width ); } /// \brief Use the two boundaries and the width to report the /// central value corresponding to a bin index - inline colvarvalue bin_to_value_scalar (int const &i_bin, int const i) const + inline colvarvalue bin_to_value_scalar(int const &i_bin, int const i) const { return lower_boundaries[i].real_value + widths[i] * (0.5 + i_bin); } /// \brief Same as the standard version, but uses different parameters - inline colvarvalue bin_to_value_scalar (int const &i_bin, + inline colvarvalue bin_to_value_scalar(int const &i_bin, colvarvalue const &new_offset, cvm::real const &new_width) const { return new_offset.real_value + new_width * (0.5 + i_bin); } /// Set the value at the point with index ix - inline void set_value (std::vector const &ix, + inline void set_value(std::vector const &ix, T const &t, size_t const &imult = 0) { - data[this->address (ix)+imult] = t; + data[this->address(ix)+imult] = t; 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 const &other_grid) + void delta_grid(colvar_grid const &other_grid) { if (other_grid.multiplicity() != this->multiplicity()) { - cvm::error ("Error: trying to subtract two grids with " + 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 " + 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 const &other_grid) + void copy_grid(colvar_grid const &other_grid) { if (other_grid.multiplicity() != this->multiplicity()) { - cvm::error ("Error: trying to copy two grids with " + cvm::error("Error: trying to copy two grids with " "different multiplicity.\n"); - return; + return; } if (other_grid.data.size() != this->data.size()) { - cvm::error ("Error: trying to copy two grids with " + 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 + 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) + 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 - inline T const & value (std::vector const &ix, + inline T const & value(std::vector const &ix, size_t const &imult = 0) const { - return data[this->address (ix) + imult]; + return data[this->address(ix) + imult]; } /// \brief Add a constant to all elements (fast loop) - inline void add_constant (T const &t) + inline void add_constant(T const &t) { for (size_t i = 0; i < nt; i++) data[i] += t; has_data = true; } /// \brief Multiply all elements by a scalar constant (fast loop) - inline void multiply_constant (cvm::real const &a) + inline void multiply_constant(cvm::real const &a) { for (size_t i = 0; i < nt; i++) data[i] *= a; } /// \brief Get the bin indices corresponding to the provided values of /// the colvars - inline std::vector const get_colvars_index (std::vector const &values) const + inline std::vector const get_colvars_index(std::vector const &values) const { std::vector index = new_index(); for (size_t i = 0; i < nd; i++) { - index[i] = value_to_bin_scalar (values[i], i); + index[i] = value_to_bin_scalar(values[i], i); } return index; } /// \brief Get the bin indices corresponding to the current values /// of the colvars inline std::vector const get_colvars_index() const { std::vector index = new_index(); for (size_t i = 0; i < nd; i++) { - index[i] = current_bin_scalar (i); + index[i] = current_bin_scalar(i); } return index; } /// \brief Get the minimal distance (in number of bins) from the /// boundaries; a negative number is returned if the given point is /// off-grid - inline cvm::real bin_distance_from_boundaries (std::vector const &values, + inline cvm::real bin_distance_from_boundaries(std::vector const &values, bool skip_hard_boundaries = false) { cvm::real minimum = 1.0E+16; for (size_t i = 0; i < nd; i++) { if (periodic[i]) continue; - cvm::real dl = std::sqrt (cv[i]->dist2 (values[i], lower_boundaries[i])) / widths[i]; - cvm::real du = std::sqrt (cv[i]->dist2 (values[i], upper_boundaries[i])) / widths[i]; + cvm::real dl = std::sqrt(cv[i]->dist2(values[i], lower_boundaries[i])) / widths[i]; + cvm::real du = std::sqrt(cv[i]->dist2(values[i], upper_boundaries[i])) / widths[i]; if (values[i].real_value < lower_boundaries[i]) dl *= -1.0; if (values[i].real_value > upper_boundaries[i]) du *= -1.0; if ( ((!skip_hard_boundaries) || (!hard_lower_boundaries[i])) && (dl < minimum)) minimum = dl; if ( ((!skip_hard_boundaries) || (!hard_upper_boundaries[i])) && (du < minimum)) minimum = du; } return minimum; } /// \brief Add data from another grid of the same type /// /// Note: this function maps other_grid inside this one regardless /// of whether it fits or not. - void map_grid (colvar_grid const &other_grid) + void map_grid(colvar_grid const &other_grid) { if (other_grid.multiplicity() != this->multiplicity()) { - cvm::error ("Error: trying to merge two grids with values of " + cvm::error("Error: trying to merge two grids with values of " "different multiplicity.\n"); return; } std::vector const &gb = this->lower_boundaries; std::vector const &gw = this->widths; std::vector const &ogb = other_grid.lower_boundaries; std::vector const &ogw = other_grid.widths; std::vector ix = this->new_index(); std::vector oix = other_grid.new_index(); if (cvm::debug()) - cvm::log ("Remapping grid...\n"); - for ( ; this->index_ok (ix); this->incr (ix)) { + cvm::log("Remapping grid...\n"); + for ( ; this->index_ok(ix); this->incr(ix)) { for (size_t i = 0; i < nd; i++) { oix[i] = - value_to_bin_scalar (bin_to_value_scalar (ix[i], gb[i], gw[i]), + value_to_bin_scalar(bin_to_value_scalar(ix[i], gb[i], gw[i]), ogb[i], ogw[i]); } - if (! other_grid.index_ok (oix)) { + if (! other_grid.index_ok(oix)) { continue; } for (size_t im = 0; im < mult; im++) { - this->set_value (ix, other_grid.value (oix, im), im); + this->set_value(ix, other_grid.value(oix, im), im); } } has_data = true; if (cvm::debug()) - cvm::log ("Remapping done.\n"); + cvm::log("Remapping done.\n"); } /// \brief Add data from another grid of the same type, AND /// identical definition (boundaries, widths) - void add_grid (colvar_grid const &other_grid, + void add_grid(colvar_grid const &other_grid, cvm::real scale_factor = 1.0) { if (other_grid.multiplicity() != this->multiplicity()) { - cvm::error ("Error: trying to sum togetehr two grids with values of " + cvm::error("Error: trying to sum togetehr two grids with values of " "different multiplicity.\n"); return; } if (scale_factor != 1.0) for (size_t i = 0; i < data.size(); i++) { data[i] += scale_factor * other_grid.data[i]; } else // skip multiplication if possible for (size_t i = 0; i < data.size(); i++) { data[i] += other_grid.data[i]; } has_data = true; } /// \brief Return the value suitable for output purposes (so that it /// may be rescaled or manipulated without changing it permanently) - virtual inline T value_output (std::vector const &ix, + virtual inline T value_output(std::vector const &ix, size_t const &imult = 0) { - return value (ix, imult); + return value(ix, imult); } /// \brief Get the value from a formatted output and transform it /// into the internal representation (the two may be different, /// e.g. when using colvar_grid_count) - virtual inline void value_input (std::vector const &ix, + virtual inline void value_input(std::vector const &ix, T const &t, size_t const &imult = 0, bool add = false) { if ( add ) - data[address (ix) + imult] += t; + data[address(ix) + imult] += t; else - data[address (ix) + imult] = t; + data[address(ix) + imult] = t; has_data = true; } // /// Get the pointer to the binned value indexed by ix // inline T const *value_p (std::vector const &ix) // { // return &(data[address (ix)]); // } /// \brief Get the index corresponding to the "first" bin, to be /// used as the initial value for an index in looping inline std::vector const new_index() const { return std::vector (nd, 0); } /// \brief Check that the index is within range in each of the /// dimensions - inline bool index_ok (std::vector const &ix) const + inline bool index_ok(std::vector const &ix) const { for (size_t i = 0; i < nd; i++) { - if ( (ix[i] < 0) || (ix[i] >= int (nx[i])) ) + if ( (ix[i] < 0) || (ix[i] >= int(nx[i])) ) return false; } return true; } /// \brief Increment the index, in a way that will make it loop over /// the whole nd-dimensional array - inline void incr (std::vector &ix) const + inline void incr(std::vector &ix) const { for (int i = ix.size()-1; i >= 0; i--) { ix[i]++; if (ix[i] >= nx[i]) { if (i > 0) { ix[i] = 0; continue; } else { // this is the last iteration, a non-valid index is being // set for the outer index, which will be caught by // index_ok() ix[0] = nx[0]; return; } } else { return; } } } /// \brief Write the grid parameters (number of colvars, boundaries, width and number of points) - std::ostream & write_params (std::ostream &os) + std::ostream & write_params(std::ostream &os) { size_t i; os << "grid_parameters {\n n_colvars " << nd << "\n"; os << " lower_boundaries "; for (i = 0; i < nd; i++) os << " " << lower_boundaries[i]; os << "\n"; os << " upper_boundaries "; for (i = 0; i < nd; i++) os << " " << upper_boundaries[i]; os << "\n"; os << " widths "; for (i = 0; i < nd; i++) os << " " << widths[i]; os << "\n"; os << " sizes "; for (i = 0; i < nd; i++) os << " " << nx[i]; os << "\n"; os << "}\n"; return os; } - bool parse_params (std::string const &conf) + bool parse_params(std::string const &conf) { std::vector old_nx = nx; std::vector old_lb = lower_boundaries; { size_t nd_in = 0; - colvarparse::get_keyval (conf, "n_colvars", nd_in, nd, colvarparse::parse_silent); + colvarparse::get_keyval(conf, "n_colvars", nd_in, nd, colvarparse::parse_silent); if (nd_in != nd) { - cvm::error ("Error: trying to read data for a grid " + cvm::error("Error: trying to read data for a grid " "that contains a different number of colvars ("+ - cvm::to_str (nd_in)+") than the grid defined " - "in the configuration file ("+cvm::to_str (nd)+ + cvm::to_str(nd_in)+") than the grid defined " + "in the configuration file("+cvm::to_str(nd)+ ").\n"); return false; } } - colvarparse::get_keyval (conf, "lower_boundaries", + colvarparse::get_keyval(conf, "lower_boundaries", lower_boundaries, lower_boundaries, colvarparse::parse_silent); - colvarparse::get_keyval (conf, "upper_boundaries", + colvarparse::get_keyval(conf, "upper_boundaries", upper_boundaries, upper_boundaries, colvarparse::parse_silent); - colvarparse::get_keyval (conf, "widths", widths, widths, colvarparse::parse_silent); + colvarparse::get_keyval(conf, "widths", widths, widths, colvarparse::parse_silent); - colvarparse::get_keyval (conf, "sizes", nx, nx, colvarparse::parse_silent); + colvarparse::get_keyval(conf, "sizes", nx, nx, colvarparse::parse_silent); bool new_params = false; for (size_t i = 0; i < nd; i++) { if ( (old_nx[i] != nx[i]) || - (std::sqrt (cv[i]->dist2 (old_lb[i], + (std::sqrt(cv[i]->dist2(old_lb[i], lower_boundaries[i])) > 1.0E-10) ) { new_params = true; } } // reallocate the array in case the grid params have just changed if (new_params) { - data.resize (0); - this->create (nx, T(), mult); + data.resize(0); + this->create(nx, T(), mult); } return true; } /// \brief Check that the grid information inside (boundaries, /// widths, ...) is consistent with the current setting of the /// colvars void check_consistency() { for (size_t i = 0; i < nd; i++) { - if ( (std::sqrt (cv[i]->dist2 (cv[i]->lower_boundary, + if ( (std::sqrt(cv[i]->dist2(cv[i]->lower_boundary, lower_boundaries[i])) > 1.0E-10) || - (std::sqrt (cv[i]->dist2 (cv[i]->upper_boundary, + (std::sqrt(cv[i]->dist2(cv[i]->upper_boundary, upper_boundaries[i])) > 1.0E-10) || - (std::sqrt (cv[i]->dist2 (cv[i]->width, + (std::sqrt(cv[i]->dist2(cv[i]->width, widths[i])) > 1.0E-10) ) { - cvm::error ("Error: restart information for a grid is " + cvm::error("Error: restart information for a grid is " "inconsistent with that of its colvars.\n"); return; } } } /// \brief Check that the grid information inside (boundaries, /// widths, ...) is consistent with that of another grid - void check_consistency (colvar_grid const &other_grid) + void check_consistency(colvar_grid const &other_grid) { for (size_t i = 0; i < nd; i++) { // we skip dist2(), because periodicities and the like should // matter: boundaries should be EXACTLY the same (otherwise, // map_grid() should be used) - if ( (std::fabs (other_grid.lower_boundaries[i] - + if ( (std::fabs(other_grid.lower_boundaries[i] - lower_boundaries[i]) > 1.0E-10) || - (std::fabs (other_grid.upper_boundaries[i] - + (std::fabs(other_grid.upper_boundaries[i] - upper_boundaries[i]) > 1.0E-10) || - (std::fabs (other_grid.widths[i] - + (std::fabs(other_grid.widths[i] - widths[i]) > 1.0E-10) || (data.size() != other_grid.data.size()) ) { - cvm::error ("Error: inconsistency between " + cvm::error("Error: inconsistency between " "two grids that are supposed to be equal, " "aside from the data stored.\n"); return; } } } /// \brief Write the grid data without labels, as they are /// represented in memory /// \param buf_size Number of values per line - std::ostream & write_raw (std::ostream &os, + std::ostream & write_raw(std::ostream &os, size_t const buf_size = 3) { std::streamsize const w = os.width(); std::streamsize const p = os.precision(); std::vector ix = new_index(); size_t count = 0; - for ( ; index_ok (ix); incr (ix)) { + for ( ; index_ok(ix); incr(ix)) { for (size_t imult = 0; imult < mult; imult++) { os << " " - << std::setw (w) << std::setprecision (p) - << value_output (ix, imult); + << std::setw(w) << std::setprecision(p) + << value_output(ix, imult); if (((++count) % buf_size) == 0) os << "\n"; } } // write a final newline only if buffer is not empty if ((count % buf_size) != 0) os << "\n"; return os; } /// \brief Read data written by colvar_grid::write_raw() - std::istream & read_raw (std::istream &is) + std::istream & read_raw(std::istream &is) { size_t const start_pos = is.tellg(); - for (std::vector ix = new_index(); index_ok (ix); incr (ix)) { + for (std::vector ix = new_index(); index_ok(ix); incr(ix)) { for (size_t imult = 0; imult < mult; imult++) { T new_value; if (is >> new_value) { - value_input (ix, new_value, imult); + value_input(ix, new_value, imult); } else { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); - cvm::error ("Error: failed to read all of the grid points from file. Possible explanations: grid parameters in the configuration (lowerBoundary, upperBoundary, width) are different from those in the file, or the file is corrupt/incomplete.\n"); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); + cvm::error("Error: failed to read all of the grid points from file. Possible explanations: grid parameters in the configuration (lowerBoundary, upperBoundary, width) are different from those in the file, or the file is corrupt/incomplete.\n"); return is; } } } has_data = true; return is; } /// \brief Write the grid in a format which is both human readable /// and suitable for visualization e.g. with gnuplot - void write_multicol (std::ostream &os) + void write_multicol(std::ostream &os) { std::streamsize const w = os.width(); std::streamsize const p = os.precision(); // Data in the header: nColvars, then for each // xiMin, dXi, nPoints, periodic - os << std::setw (2) << "# " << nd << "\n"; + os << std::setw(2) << "# " << nd << "\n"; for (size_t i = 0; i < nd; i++) { os << "# " - << std::setw (10) << lower_boundaries[i] - << std::setw (10) << widths[i] - << std::setw (10) << nx[i] << " " + << std::setw(10) << lower_boundaries[i] + << std::setw(10) << widths[i] + << std::setw(10) << nx[i] << " " << periodic[i] << "\n"; } - for (std::vector ix = new_index(); index_ok (ix); incr (ix) ) { + for (std::vector ix = new_index(); index_ok(ix); incr(ix) ) { if (ix.back() == 0) { // if the last index is 0, add a new line to mark the new record os << "\n"; } for (size_t i = 0; i < nd; i++) { os << " " - << std::setw (w) << std::setprecision (p) - << bin_to_value_scalar (ix[i], i); + << std::setw(w) << std::setprecision(p) + << bin_to_value_scalar(ix[i], i); } os << " "; for (size_t imult = 0; imult < mult; imult++) { os << " " - << std::setw (w) << std::setprecision (p) - << value_output (ix, imult); + << std::setw(w) << std::setprecision(p) + << value_output(ix, imult); } os << "\n"; } } /// \brief Read a grid written by colvar_grid::write_multicol() /// Adding data if add is true, replacing if false - std::istream & read_multicol (std::istream &is, bool add = false) + std::istream & read_multicol(std::istream &is, bool add = false) { // Data in the header: nColvars, then for each // xiMin, dXi, nPoints, periodic std::string hash; cvm::real lower, width, x; size_t n, periodic; bool remap; std::vector new_value; std::vector nx_read; std::vector bin; if ( cv.size() != nd ) { - cvm::error ("Cannot read grid file: missing reference to colvars."); + cvm::error("Cannot read grid file: missing reference to colvars."); return is; } if ( !(is >> hash) || (hash != "#") ) { - cvm::error ("Error reading grid at position "+ - cvm::to_str (is.tellg())+" in stream (read \"" + hash + "\")\n"); + cvm::error("Error reading grid at position "+ + cvm::to_str(is.tellg())+" in stream(read \"" + hash + "\")\n"); return is; } is >> n; if ( n != nd ) { - cvm::error ("Error reading grid: wrong number of collective variables.\n"); + cvm::error("Error reading grid: wrong number of collective variables.\n"); return is; } - nx_read.resize (n); - bin.resize (n); - new_value.resize (mult); + nx_read.resize(n); + bin.resize(n); + new_value.resize(mult); if (this->has_parent_data && add) { - new_data.resize (data.size()); + new_data.resize(data.size()); } remap = false; for (size_t i = 0; i < nd; i++ ) { if ( !(is >> hash) || (hash != "#") ) { - cvm::error ("Error reading grid at position "+ - cvm::to_str (is.tellg())+" in stream (read \"" + hash + "\")\n"); + cvm::error("Error reading grid at position "+ + cvm::to_str(is.tellg())+" in stream(read \"" + hash + "\")\n"); return is; } is >> lower >> width >> nx_read[i] >> periodic; - if ( (std::fabs (lower - lower_boundaries[i].real_value) > 1.0e-10) || - (std::fabs (width - widths[i] ) > 1.0e-10) || + if ( (std::fabs(lower - lower_boundaries[i].real_value) > 1.0e-10) || + (std::fabs(width - widths[i] ) > 1.0e-10) || (nx_read[i] != nx[i]) ) { - cvm::log ("Warning: reading from different grid definition (colvar " - + cvm::to_str (i+1) + "); remapping data on new grid.\n"); + cvm::log("Warning: reading from different grid definition (colvar " + + cvm::to_str(i+1) + "); remapping data on new grid.\n"); remap = true; } } if ( remap ) { // re-grid data while (is.good()) { bool end_of_file = false; for (size_t i = 0; i < nd; i++ ) { if ( !(is >> x) ) end_of_file = true; - bin[i] = value_to_bin_scalar (x, i); + bin[i] = value_to_bin_scalar(x, i); } if (end_of_file) break; for (size_t imult = 0; imult < mult; imult++) { is >> new_value[imult]; } if ( index_ok(bin) ) { for (size_t imult = 0; imult < mult; imult++) { - value_input (bin, new_value[imult], imult, add); + value_input(bin, new_value[imult], imult, add); } } } } else { // do not re-grid the data but assume the same grid is used - for (std::vector ix = new_index(); index_ok (ix); incr (ix) ) { + for (std::vector ix = new_index(); index_ok(ix); incr(ix) ) { for (size_t i = 0; i < nd; i++ ) { is >> x; } for (size_t imult = 0; imult < mult; imult++) { is >> new_value[imult]; - value_input (ix, new_value[imult], imult, add); + value_input(ix, new_value[imult], imult, add); } } } has_data = true; return is; } }; /// \brief Colvar_grid derived class to hold counters in discrete /// n-dim colvar space class colvar_grid_count : public colvar_grid { public: /// Default constructor colvar_grid_count(); /// Destructor virtual inline ~colvar_grid_count() {} /// Constructor - colvar_grid_count (std::vector const &nx_i, + colvar_grid_count(std::vector const &nx_i, size_t const &def_count = 0); /// Constructor from a vector of colvars - colvar_grid_count (std::vector &colvars, + colvar_grid_count(std::vector &colvars, size_t const &def_count = 0); /// Increment the counter at given position - inline void incr_count (std::vector const &ix) + inline void incr_count(std::vector const &ix) { - ++(data[this->address (ix)]); + ++(data[this->address(ix)]); } /// \brief Get the binned count indexed by ix from the newly read data - inline size_t const & new_count (std::vector const &ix, + inline size_t const & new_count(std::vector const &ix, size_t const &imult = 0) { - return new_data[address (ix) + imult]; + return new_data[address(ix) + imult]; } /// \brief Read the grid from a restart - std::istream & read_restart (std::istream &is); + std::istream & read_restart(std::istream &is); /// \brief Write the grid to a restart - std::ostream & write_restart (std::ostream &os); + std::ostream & write_restart(std::ostream &os); /// \brief Get the value from a formatted output and transform it /// into the internal representation (it may have been rescaled or /// manipulated) - virtual inline void value_input (std::vector const &ix, + virtual inline void value_input(std::vector const &ix, size_t const &t, size_t const &imult = 0, bool add = false) { if (add) { - data[address (ix)] += t; + data[address(ix)] += t; if (this->has_parent_data) { // save newly read data for inputting parent grid - new_data[address (ix)] = t; + new_data[address(ix)] = t; } } else { - data[address (ix)] = t; + data[address(ix)] = t; } has_data = true; } }; /// Class for accumulating a scalar function on a grid class colvar_grid_scalar : public colvar_grid { public: /// \brief Provide the associated sample count by which each binned value /// should be divided colvar_grid_count *samples; /// Default constructor colvar_grid_scalar(); /// Copy constructor (needed because of the grad pointer) - colvar_grid_scalar (colvar_grid_scalar const &g); + colvar_grid_scalar(colvar_grid_scalar const &g); /// Destructor ~colvar_grid_scalar(); /// Constructor from specific sizes arrays - colvar_grid_scalar (std::vector const &nx_i); + colvar_grid_scalar(std::vector const &nx_i); /// Constructor from a vector of colvars - colvar_grid_scalar (std::vector &colvars, + colvar_grid_scalar(std::vector &colvars, bool margin = 0); /// Accumulate the value - inline void acc_value (std::vector const &ix, + inline void acc_value(std::vector const &ix, cvm::real const &new_value, size_t const &imult = 0) { // only legal value of imult here is 0 - data[address (ix)] += new_value; + data[address(ix)] += new_value; if (samples) - samples->incr_count (ix); + samples->incr_count(ix); has_data = true; } /// Return the gradient of the scalar field from finite differences - inline const cvm::real * gradient_finite_diff ( const std::vector &ix0 ) + inline const cvm::real * gradient_finite_diff( const std::vector &ix0 ) { cvm::real A0, A1; std::vector ix; if (nd != 2) { - cvm::error ("Finite differences available in dimension 2 only."); + cvm::error("Finite differences available in dimension 2 only."); return grad; } for (unsigned int n = 0; n < nd; n++) { ix = ix0; - A0 = data[address (ix)]; - ix[n]++; wrap (ix); - A1 = data[address (ix)]; - ix[1-n]++; wrap (ix); - A1 += data[address (ix)]; - ix[n]--; wrap (ix); - A0 += data[address (ix)]; + A0 = data[address(ix)]; + ix[n]++; wrap(ix); + A1 = data[address(ix)]; + ix[1-n]++; wrap(ix); + A1 += data[address(ix)]; + ix[n]--; wrap(ix); + A0 += data[address(ix)]; grad[n] = 0.5 * (A1 - A0) / widths[n]; } return grad; } /// \brief Return the value of the function at ix divided by its /// number of samples (if the count grid is defined) - virtual cvm::real value_output (std::vector const &ix, + virtual cvm::real value_output(std::vector const &ix, size_t const &imult = 0) { if (imult > 0) { - cvm::error ("Error: trying to access a component " + cvm::error("Error: trying to access a component " "larger than 1 in a scalar data grid.\n"); return 0.; } if (samples) - return (samples->value (ix) > 0) ? - (data[address (ix)] / cvm::real (samples->value (ix))) : + return (samples->value(ix) > 0) ? + (data[address(ix)] / cvm::real(samples->value(ix))) : 0.0; else - return data[address (ix)]; + return data[address(ix)]; } /// \brief Get the value from a formatted output and transform it /// into the internal representation (it may have been rescaled or /// manipulated) - virtual void value_input (std::vector const &ix, + virtual void value_input(std::vector const &ix, cvm::real const &new_value, size_t const &imult = 0, bool add = false) { if (imult > 0) { - cvm::error ("Error: trying to access a component " + cvm::error("Error: trying to access a component " "larger than 1 in a scalar data grid.\n"); return; } if (add) { if (samples) - data[address (ix)] += new_value * samples->new_count (ix); + data[address(ix)] += new_value * samples->new_count(ix); else - data[address (ix)] += new_value; + data[address(ix)] += new_value; } else { if (samples) - data[address (ix)] = new_value * samples->value (ix); + data[address(ix)] = new_value * samples->value(ix); else - data[address (ix)] = new_value; + data[address(ix)] = new_value; } has_data = true; } /// \brief Read the grid from a restart - std::istream & read_restart (std::istream &is); + std::istream & read_restart(std::istream &is); /// \brief Write the grid to a restart - std::ostream & write_restart (std::ostream &os); + std::ostream & write_restart(std::ostream &os); /// \brief Return the highest value inline cvm::real maximum_value() { cvm::real max = data[0]; for (size_t i = 0; i < nt; i++) { if (data[i] > max) max = data[i]; } return max; } /// \brief Return the lowest value inline cvm::real minimum_value() { cvm::real min = data[0]; for (size_t i = 0; i < nt; i++) { if (data[i] < min) min = data[i]; } return min; } private: // gradient cvm::real * grad; }; /// Class for accumulating the gradient of a scalar function on a grid class colvar_grid_gradient : public colvar_grid { public: /// \brief Provide the sample count by which each binned value /// should be divided colvar_grid_count *samples; /// Default constructor colvar_grid_gradient(); /// Destructor virtual inline ~colvar_grid_gradient() {} /// Constructor from specific sizes arrays - colvar_grid_gradient (std::vector const &nx_i); + colvar_grid_gradient(std::vector const &nx_i); /// Constructor from a vector of colvars - colvar_grid_gradient (std::vector &colvars); + colvar_grid_gradient(std::vector &colvars); /// \brief Accumulate the gradient - inline void acc_grad (std::vector const &ix, cvm::real const *grads) { + inline void acc_grad(std::vector const &ix, cvm::real const *grads) { for (size_t imult = 0; imult < mult; imult++) { - data[address (ix) + imult] += grads[imult]; + data[address(ix) + imult] += grads[imult]; } if (samples) - samples->incr_count (ix); + samples->incr_count(ix); } /// \brief Accumulate the gradient based on the force (i.e. sums the /// opposite of the force) - inline void acc_force (std::vector const &ix, cvm::real const *forces) { + inline void acc_force(std::vector const &ix, cvm::real const *forces) { for (size_t imult = 0; imult < mult; imult++) { - data[address (ix) + imult] -= forces[imult]; + data[address(ix) + imult] -= forces[imult]; } if (samples) - samples->incr_count (ix); + samples->incr_count(ix); } /// \brief Return the value of the function at ix divided by its /// number of samples (if the count grid is defined) - virtual inline cvm::real value_output (std::vector const &ix, + virtual inline cvm::real value_output(std::vector const &ix, size_t const &imult = 0) { if (samples) - return (samples->value (ix) > 0) ? - (data[address (ix) + imult] / cvm::real (samples->value (ix))) : + return (samples->value(ix) > 0) ? + (data[address(ix) + imult] / cvm::real(samples->value(ix))) : 0.0; else - return data[address (ix) + imult]; + return data[address(ix) + imult]; } /// \brief Get the value from a formatted output and transform it /// into the internal representation (it may have been rescaled or /// manipulated) - virtual inline void value_input (std::vector const &ix, + virtual inline void value_input(std::vector const &ix, cvm::real const &new_value, size_t const &imult = 0, bool add = false) { if (add) { if (samples) - data[address (ix) + imult] += new_value * samples->new_count (ix); + data[address(ix) + imult] += new_value * samples->new_count(ix); else - data[address (ix) + imult] += new_value; + data[address(ix) + imult] += new_value; } else { if (samples) - data[address (ix) + imult] = new_value * samples->value (ix); + data[address(ix) + imult] = new_value * samples->value(ix); else - data[address (ix) + imult] = new_value; + data[address(ix) + imult] = new_value; } has_data = true; } /// \brief Read the grid from a restart - std::istream & read_restart (std::istream &is); + std::istream & read_restart(std::istream &is); /// \brief Write the grid to a restart - std::ostream & write_restart (std::ostream &os); + std::ostream & write_restart(std::ostream &os); /// Compute and return average value for a 1D gradient grid inline cvm::real average() { size_t n = 0; if (nd != 1 || nx[0] == 0) { return 0.0; } cvm::real sum = 0.0; std::vector ix = new_index(); if (samples) { - for ( ; index_ok (ix); incr (ix)) { - if ( (n = samples->value (ix)) ) - sum += value (ix) / n; + for ( ; index_ok(ix); incr(ix)) { + if ( (n = samples->value(ix)) ) + sum += value(ix) / n; } } else { - for ( ; index_ok (ix); incr (ix)) { - sum += value (ix); + for ( ; index_ok(ix); incr(ix)) { + sum += value(ix); } } - return (sum / cvm::real (nx[0])); + return (sum / cvm::real(nx[0])); } /// \brief If the grid is 1-dimensional, integrate it and write the /// integral to a file - void write_1D_integral (std::ostream &os); + void write_1D_integral(std::ostream &os); }; #endif diff --git a/lib/colvars/colvarmodule.cpp b/lib/colvars/colvarmodule.cpp index 03f9ba704..252808892 100644 --- a/lib/colvars/colvarmodule.cpp +++ b/lib/colvars/colvarmodule.cpp @@ -1,1347 +1,1212 @@ /// -*- c++ -*- #include +#include + #include "colvarmodule.h" #include "colvarparse.h" #include "colvarproxy.h" #include "colvar.h" #include "colvarbias.h" #include "colvarbias_alb.h" #include "colvarbias_meta.h" #include "colvarbias_abf.h" #include "colvarbias_restraint.h" #include "colvarscript.h" -colvarmodule::colvarmodule (colvarproxy *proxy_in) +colvarmodule::colvarmodule(colvarproxy *proxy_in) { // pointer to the proxy object if (proxy == NULL) { proxy = proxy_in; parse = new colvarparse(); } else { // TODO relax this error to handle multiple molecules in VMD // once the module is not static anymore - cvm::error ("Error: trying to allocate the collective " + cvm::error("Error: trying to allocate the collective " "variable module twice.\n"); return; } - cvm::log (cvm::line_marker); - cvm::log ("Initializing the collective variables module, version "+ - cvm::to_str (COLVARS_VERSION)+".\n"); + cvm::log(cvm::line_marker); + cvm::log("Initializing the collective variables module, version "+ + cvm::to_str(COLVARS_VERSION)+".\n"); // set initial default values // "it_restart" will be set by the input state file, if any; // "it" should be updated by the proxy colvarmodule::it = colvarmodule::it_restart = 0; colvarmodule::it_restart_from_state_file = true; colvarmodule::use_scripted_forces = false; colvarmodule::b_analysis = false; colvarmodule::debug_gradients_step_size = 1.0e-07; colvarmodule::rotation::crossing_threshold = 1.0e-02; colvarmodule::cv_traj_freq = 100; colvarmodule::restart_out_freq = proxy->restart_frequency(); // by default overwrite the existing trajectory file colvarmodule::cv_traj_append = false; } -int colvarmodule::config_file (char const *config_filename) +int colvarmodule::config_file(char const *config_filename) { - cvm::log (cvm::line_marker); - cvm::log ("Reading new configuration from file \""+ - std::string (config_filename)+"\":\n"); + cvm::log(cvm::line_marker); + cvm::log("Reading new configuration from file \""+ + std::string(config_filename)+"\":\n"); // open the configfile - config_s.open (config_filename); + config_s.open(config_filename); if (!config_s) { - cvm::error ("Error: in opening configuration file \""+ - std::string (config_filename)+"\".\n", + cvm::error("Error: in opening configuration file \""+ + std::string(config_filename)+"\".\n", FILE_ERROR); return COLVARS_ERROR; } // read the config file into a string std::string conf = ""; std::string line; - while (colvarparse::getline_nocomments (config_s, line)) { - conf.append (line+"\n"); + while (colvarparse::getline_nocomments(config_s, line)) { + conf.append(line+"\n"); } config_s.close(); - return config (conf); + return config(conf); } -int colvarmodule::config_string (std::string const &config_str) +int colvarmodule::config_string(std::string const &config_str) { - cvm::log (cvm::line_marker); - cvm::log ("Reading new configuration:\n"); - std::istringstream config_s (config_str); + cvm::log(cvm::line_marker); + cvm::log("Reading new configuration:\n"); + std::istringstream config_s(config_str); // strip the comments away std::string conf = ""; std::string line; - while (colvarparse::getline_nocomments (config_s, line)) { - conf.append (line+"\n"); + while (colvarparse::getline_nocomments(config_s, line)) { + conf.append(line+"\n"); } - return config (conf); + return config(conf); } -int colvarmodule::config (std::string &conf) +int colvarmodule::config(std::string &conf) { int error_code = 0; // parse global options - error_code |= parse_global_params (conf); + error_code |= parse_global_params(conf); if (error_code != COLVARS_OK || cvm::get_error()) { set_error_bits(INPUT_ERROR); return COLVARS_ERROR; } // parse the options for collective variables - error_code |= parse_colvars (conf); + 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); + 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"); + error_code |= parse->check_keywords(conf, "colvarmodule"); if (error_code != COLVARS_OK || cvm::get_error()) { set_error_bits(INPUT_ERROR); return COLVARS_ERROR; } - cvm::log (cvm::line_marker); - cvm::log ("Collective variables module (re)initialized.\n"); - cvm::log (cvm::line_marker); + cvm::log(cvm::line_marker); + cvm::log("Collective variables module (re)initialized.\n"); + cvm::log(cvm::line_marker); // configuration might have changed, better redo the labels write_traj_label(cv_traj_os); return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -int colvarmodule::parse_global_params (std::string const &conf) +int colvarmodule::parse_global_params(std::string const &conf) { std::string index_file_name; - if (parse->get_keyval (conf, "indexFile", index_file_name)) { - read_index_file (index_file_name.c_str()); + if (parse->get_keyval(conf, "indexFile", index_file_name)) { + read_index_file(index_file_name.c_str()); } - parse->get_keyval (conf, "analysis", b_analysis, b_analysis); + parse->get_keyval(conf, "analysis", b_analysis, b_analysis); - parse->get_keyval (conf, "debugGradientsStepSize", debug_gradients_step_size, + parse->get_keyval(conf, "debugGradientsStepSize", debug_gradients_step_size, debug_gradients_step_size, colvarparse::parse_silent); - parse->get_keyval (conf, "eigenvalueCrossingThreshold", + parse->get_keyval(conf, "eigenvalueCrossingThreshold", colvarmodule::rotation::crossing_threshold, colvarmodule::rotation::crossing_threshold, colvarparse::parse_silent); - parse->get_keyval (conf, "colvarsTrajFrequency", cv_traj_freq, cv_traj_freq); - parse->get_keyval (conf, "colvarsRestartFrequency", + parse->get_keyval(conf, "colvarsTrajFrequency", cv_traj_freq, cv_traj_freq); + parse->get_keyval(conf, "colvarsRestartFrequency", restart_out_freq, restart_out_freq); // if this is true when initializing, it means // we are continuing after a reset(): default to true - parse->get_keyval (conf, "colvarsTrajAppend", cv_traj_append, cv_traj_append); + parse->get_keyval(conf, "colvarsTrajAppend", cv_traj_append, cv_traj_append); - parse->get_keyval (conf, "scriptedColvarForces", use_scripted_forces, false, + parse->get_keyval(conf, "scriptedColvarForces", use_scripted_forces, false, colvarparse::parse_silent); if (use_scripted_forces && !proxy->force_script_defined) { - cvm::fatal_error("User script for scripted colvars forces not found."); + cvm::fatal_error("User script for scripted colvar forces not found."); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -int colvarmodule::parse_colvars (std::string const &conf) +int colvarmodule::parse_colvars(std::string const &conf) { if (cvm::debug()) - cvm::log ("Initializing the collective variables.\n"); + cvm::log("Initializing the collective variables.\n"); std::string colvar_conf = ""; size_t pos = 0; - while (parse->key_lookup (conf, "colvar", colvar_conf, pos)) { + while (parse->key_lookup(conf, "colvar", colvar_conf, pos)) { if (colvar_conf.size()) { - cvm::log (cvm::line_marker); + cvm::log(cvm::line_marker); cvm::increase_depth(); - colvars.push_back (new colvar (colvar_conf)); + colvars.push_back(new colvar(colvar_conf)); if (cvm::get_error() || - ((colvars.back())->check_keywords (colvar_conf, "colvar") != COLVARS_OK)) { + ((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(); } else { cvm::error("Error: \"colvar\" keyword found without any configuration.\n", INPUT_ERROR); return COLVARS_ERROR; } cvm::decrease_depth(); colvar_conf = ""; } if (!colvars.size()) { - cvm::log ("Warning: no collective variables defined.\n"); + cvm::log("Warning: no collective variables defined.\n"); } if (colvars.size()) - cvm::log (cvm::line_marker); - cvm::log ("Collective variables initialized, "+ - cvm::to_str (colvars.size())+ + cvm::log(cvm::line_marker); + cvm::log("Collective variables initialized, "+ + cvm::to_str(colvars.size())+ " in total.\n"); 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) -{ - if (cvm::debug()) - cvm::log ("Initializing the collective variables biases.\n"); - { - /// initialize ABF instances - std::string abf_conf = ""; - size_t abf_pos = 0; - while (parse->key_lookup (conf, "abf", abf_conf, abf_pos)) { - if (abf_conf.size()) { - cvm::log (cvm::line_marker); - cvm::increase_depth(); - biases.push_back (new colvarbias_abf (abf_conf, "abf")); - if (cvm::check_new_bias(abf_conf, "abf")) { - return COLVARS_ERROR; - } - cvm::decrease_depth(); - n_abf_biases++; - } else { - cvm::error("Error: \"abf\" keyword found without configuration.\n", INPUT_ERROR); +template +int colvarmodule::parse_biases_type(std::string const &conf, + char const *keyword, + size_t &bias_count) +{ + std::string bias_conf = ""; + size_t conf_saved_pos = 0; + while (parse->key_lookup(conf, keyword, bias_conf, conf_saved_pos)) { + if (bias_conf.size()) { + cvm::log(cvm::line_marker); + cvm::increase_depth(); + biases.push_back(new bias_type(bias_conf, keyword)); + if (cvm::check_new_bias(bias_conf, keyword)) { return COLVARS_ERROR; } - abf_conf = ""; + cvm::decrease_depth(); + bias_count++; + } else { + cvm::error("Error: keyword \""+std::string(keyword)+"\" found without configuration.\n", + INPUT_ERROR); + return COLVARS_ERROR; } + bias_conf = ""; } + return COLVARS_OK; +} - { - /// initialize harmonic restraints - std::string harm_conf = ""; - size_t harm_pos = 0; - while (parse->key_lookup (conf, "harmonic", harm_conf, harm_pos)) { - if (harm_conf.size()) { - cvm::log (cvm::line_marker); - cvm::increase_depth(); - biases.push_back (new colvarbias_restraint_harmonic (harm_conf, "harmonic")); - if (cvm::check_new_bias(harm_conf, "harmonic")) { - return COLVARS_ERROR; - } - cvm::decrease_depth(); - n_rest_biases++; - } else { - cvm::error("Error: \"harmonic\" keyword found without configuration.\n", INPUT_ERROR); - return COLVARS_ERROR; - } - harm_conf = ""; - } - } - { - /// initialize linear restraints - std::string lin_conf = ""; - size_t lin_pos = 0; - while (parse->key_lookup (conf, "linear", lin_conf, lin_pos)) { - if (lin_conf.size()) { - cvm::log (cvm::line_marker); - cvm::increase_depth(); - biases.push_back (new colvarbias_restraint_linear (lin_conf, "linear")); - if (cvm::check_new_bias(lin_conf, "linear")) { - return COLVARS_ERROR; - } - cvm::decrease_depth(); - n_rest_biases++; - } else { - cvm::error("Error: \"linear\" keyword found without configuration.\n", INPUT_ERROR); - return COLVARS_ERROR; - } - lin_conf = ""; - } - } +int colvarmodule::parse_biases(std::string const &conf) +{ + if (cvm::debug()) + cvm::log("Initializing the collective variables biases.\n"); - { - /// initialize adaptive linear biases - std::string alb_conf = ""; - size_t alb_pos = 0; - while (parse->key_lookup (conf, "ALB", alb_conf, alb_pos)) { - if (alb_conf.size()) { - cvm::log (cvm::line_marker); - cvm::increase_depth(); - biases.push_back (new colvarbias_alb (alb_conf, "ALB")); - if (cvm::check_new_bias(alb_conf, "ALB")) { - return COLVARS_ERROR; - } - cvm::decrease_depth(); - n_rest_biases++; - } else { - cvm::error("Error: \"ALB\" keyword found without configuration.\n", INPUT_ERROR); - return COLVARS_ERROR; - } - alb_conf = ""; - } - } + /// initialize ABF instances + parse_biases_type(conf, "abf", n_abf_biases); + /// initialize adaptive linear biases + parse_biases_type(conf, "ALB", n_rest_biases); - { - /// initialize histograms - std::string histo_conf = ""; - size_t histo_pos = 0; - while (parse->key_lookup (conf, "histogram", histo_conf, histo_pos)) { - if (histo_conf.size()) { - cvm::log (cvm::line_marker); - cvm::increase_depth(); - biases.push_back (new colvarbias_histogram (histo_conf, "histogram")); - if (cvm::check_new_bias(histo_conf, "histogram")) { - return COLVARS_ERROR; - } - cvm::decrease_depth(); - n_histo_biases++; - } else { - cvm::error("Error: \"histogram\" keyword found without configuration.\n", INPUT_ERROR); - return COLVARS_ERROR; - } - histo_conf = ""; - } - } + /// initialize harmonic restraints + parse_biases_type(conf, "harmonic", n_rest_biases); - { - /// initialize metadynamics instances - std::string meta_conf = ""; - size_t meta_pos = 0; - while (parse->key_lookup (conf, "metadynamics", meta_conf, meta_pos)) { - if (meta_conf.size()) { - cvm::log (cvm::line_marker); - cvm::increase_depth(); - biases.push_back (new colvarbias_meta (meta_conf, "metadynamics")); - if (cvm::check_new_bias(meta_conf, "metadynamics")) { - return COLVARS_ERROR; - } - cvm::decrease_depth(); - n_meta_biases++; - } else { - cvm::error("Error: \"metadynamics\" keyword found without configuration.\n", INPUT_ERROR); - return COLVARS_ERROR; - } - meta_conf = ""; - } - } + /// initialize histograms + parse_biases_type(conf, "histogram", n_histo_biases); + + /// initialize linear restraints + parse_biases_type(conf, "linear", n_rest_biases); + + /// initialize metadynamics instances + parse_biases_type(conf, "metadynamics", n_meta_biases); if (use_scripted_forces) { - cvm::log (cvm::line_marker); + cvm::log(cvm::line_marker); cvm::increase_depth(); cvm::log("User forces script will be run at each bias update."); cvm::decrease_depth(); } - if (biases.size() || use_scripted_forces) - cvm::log (cvm::line_marker); - cvm::log ("Collective variables biases initialized, "+ - cvm::to_str (biases.size())+" in total.\n"); + if (biases.size() || use_scripted_forces) { + cvm::log(cvm::line_marker); + cvm::log("Collective variables biases initialized, "+ + cvm::to_str(biases.size())+" in total.\n"); + } else { + if (!use_scripted_forces) { + cvm::log("No collective variables biases were defined.\n"); + } + } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } colvarbias * colvarmodule::bias_by_name(std::string const &name) { for (std::vector::iterator bi = biases.begin(); bi != biases.end(); bi++) { if ((*bi)->name == name) { return (*bi); } } return NULL; } colvar *colvarmodule::colvar_by_name(std::string const &name) { for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { if ((*cvi)->name == name) { return (*cvi); } } return NULL; } -int colvarmodule::change_configuration (std::string const &bias_name, +int colvarmodule::change_configuration(std::string const &bias_name, std::string const &conf) { // This is deprecated; supported strategy is to delete the bias // and parse the new config cvm::increase_depth(); colvarbias *b; - b = bias_by_name (bias_name); - if (b == NULL) { cvm::error ("Error: bias not found: " + bias_name); } - b->change_configuration (conf); + b = bias_by_name(bias_name); + if (b == NULL) { cvm::error("Error: bias not found: " + bias_name); } + b->change_configuration(conf); cvm::decrease_depth(); return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } std::string colvarmodule::read_colvar(std::string const &name) { cvm::increase_depth(); colvar *c; std::stringstream ss; - c = colvar_by_name (name); - if (c == NULL) { cvm::fatal_error ("Error: colvar not found: " + name); } + c = colvar_by_name(name); + if (c == NULL) { cvm::fatal_error("Error: colvar not found: " + name); } ss << c->value(); cvm::decrease_depth(); return ss.str(); } -cvm::real colvarmodule::energy_difference (std::string const &bias_name, +cvm::real colvarmodule::energy_difference(std::string const &bias_name, std::string const &conf) { cvm::increase_depth(); colvarbias *b; cvm::real energy_diff = 0.; - b = bias_by_name (bias_name); - if (b == NULL) { cvm::fatal_error ("Error: bias not found: " + bias_name); } - energy_diff = b->energy_difference (conf); + b = bias_by_name(bias_name); + if (b == NULL) { cvm::fatal_error("Error: bias not found: " + bias_name); } + energy_diff = b->energy_difference(conf); cvm::decrease_depth(); return energy_diff; } -// For shared ABF -cvm::real colvarmodule::read_width(std::string const &name) +int colvarmodule::bias_current_bin(std::string const &bias_name) { cvm::increase_depth(); - int found = 0; - real width = -1.0; - for (std::vector::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; -} + int ret; + colvarbias *b = bias_by_name(bias_name); -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::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"); + if (b != NULL) { + ret = b->current_bin(); } else { - cvm::decrease_depth(); + cvm::error("Error: bias not found.\n"); + ret = COLVARS_ERROR; } + + cvm::decrease_depth(); return ret; } -size_t colvarmodule::bias_bin_num (std::string const &bias_name) +int 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. + int ret; + colvarbias *b = bias_by_name(bias_name); - for (std::vector::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"); + if (b != NULL) { + ret = b->bin_num(); } else { - cvm::decrease_depth(); + cvm::error("Error: bias not found.\n"); + ret = COLVARS_ERROR; } + + cvm::decrease_depth(); return ret; } -size_t colvarmodule::bias_bin_count (std::string const &bias_name, size_t bin_index) +int 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. + int ret; + colvarbias *b = bias_by_name(bias_name); - for (std::vector::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"); + if (b != NULL) { + ret = b->bin_count(bin_index); } else { - cvm::decrease_depth(); + cvm::error("Error: bias not found.\n"); + ret = COLVARS_ERROR; } + + cvm::decrease_depth(); return ret; } -void colvarmodule::bias_share (std::string const &bias_name) +int colvarmodule::bias_share(std::string const &bias_name) { cvm::increase_depth(); - int found = 0; + int ret; + colvarbias *b = bias_by_name(bias_name); - for (std::vector::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; + if (b != NULL) { + b->replica_share(); + ret = COLVARS_OK; + } else { + cvm::error("Error: bias not found.\n"); + ret = COLVARS_ERROR; } + cvm::decrease_depth(); + return ret; } int colvarmodule::calc() { cvm::real total_bias_energy = 0.0; cvm::real total_colvar_energy = 0.0; std::vector::iterator cvi; std::vector::iterator bi; if (cvm::debug()) { - cvm::log (cvm::line_marker); - cvm::log ("Collective variables module, step no. "+ - cvm::to_str (cvm::step_absolute())+"\n"); + cvm::log(cvm::line_marker); + cvm::log("Collective variables module, step no. "+ + cvm::to_str(cvm::step_absolute())+"\n"); } // calculate collective variables and their gradients if (cvm::debug()) - cvm::log ("Calculating collective variables.\n"); + cvm::log("Calculating collective variables.\n"); cvm::increase_depth(); for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { (*cvi)->calc(); if (cvm::get_error()) { return COLVARS_ERROR; } } cvm::decrease_depth(); // update the biases and communicate their forces to the collective // variables if (cvm::debug() && biases.size()) - cvm::log ("Updating collective variable biases.\n"); + cvm::log("Updating collective variable biases.\n"); cvm::increase_depth(); for (bi = biases.begin(); bi != biases.end(); bi++) { total_bias_energy += (*bi)->update(); if (cvm::get_error()) { return COLVARS_ERROR; } } cvm::decrease_depth(); // sum the forces from all biases for each collective variable if (cvm::debug() && biases.size()) - cvm::log ("Collecting forces from all biases.\n"); + cvm::log("Collecting forces from all biases.\n"); cvm::increase_depth(); for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { (*cvi)->reset_bias_force(); } for (bi = biases.begin(); bi != biases.end(); bi++) { (*bi)->communicate_forces(); if (cvm::get_error()) { return COLVARS_ERROR; } } // Run user force script, if provided, // potentially adding scripted forces to the colvars if (use_scripted_forces) { int res; res = proxy->run_force_callback(); if (res == COLVARS_NOT_IMPLEMENTED) { cvm::error("Colvar forces scripts are not implemented."); return COLVARS_ERROR; } if (res != COLVARS_OK) { cvm::error("Error running user colvar forces script"); return COLVARS_ERROR; } } cvm::decrease_depth(); if (cvm::b_analysis) { // perform runtime analysis of colvars and biases if (cvm::debug() && biases.size()) - cvm::log ("Perform runtime analyses.\n"); + cvm::log("Perform runtime analyses.\n"); cvm::increase_depth(); for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { (*cvi)->analyse(); if (cvm::get_error()) { return COLVARS_ERROR; } } for (bi = biases.begin(); bi != biases.end(); bi++) { (*bi)->analyse(); if (cvm::get_error()) { return COLVARS_ERROR; } } cvm::decrease_depth(); } // sum up the forces for each colvar, including wall forces // and integrate any internal // equation of motion (extended system) if (cvm::debug()) - cvm::log ("Updating the internal degrees of freedom " + cvm::log("Updating the internal degrees of freedom " "of colvars (if they have any).\n"); cvm::increase_depth(); for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { total_colvar_energy += (*cvi)->update(); if (cvm::get_error()) { return COLVARS_ERROR; } } cvm::decrease_depth(); - proxy->add_energy (total_bias_energy + total_colvar_energy); + proxy->add_energy(total_bias_energy + total_colvar_energy); // make collective variables communicate their forces to their // coupled degrees of freedom (i.e. atoms) if (cvm::debug()) - cvm::log ("Communicating forces from the colvars to the atoms.\n"); + cvm::log("Communicating forces from the colvars to the atoms.\n"); cvm::increase_depth(); for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { if ((*cvi)->tasks[colvar::task_gradients]) { (*cvi)->communicate_forces(); if (cvm::get_error()) { return COLVARS_ERROR; } } } cvm::decrease_depth(); // write restart file, if needed if (restart_out_freq && restart_out_name.size()) { if ( (cvm::step_relative() > 0) && ((cvm::step_absolute() % restart_out_freq) == 0) ) { - cvm::log ("Writing the state file \""+ + cvm::log("Writing the state file \""+ restart_out_name+"\".\n"); - proxy->backup_file (restart_out_name.c_str()); - restart_out_os.open (restart_out_name.c_str()); - if (!write_restart (restart_out_os)) - cvm::error ("Error: in writing restart file.\n"); + proxy->backup_file(restart_out_name.c_str()); + restart_out_os.open(restart_out_name.c_str()); + if (!write_restart(restart_out_os)) + cvm::error("Error: in writing restart file.\n"); restart_out_os.close(); } } // write trajectory file, if needed if (cv_traj_freq && cv_traj_name.size()) { - if (!cv_traj_os.good()) { - open_traj_file (cv_traj_name); + if (!cv_traj_os.is_open()) { + open_traj_file(cv_traj_name); } // write labels in the traj file every 1000 lines and at first timestep if ((cvm::step_absolute() % (cv_traj_freq * 1000)) == 0 || cvm::step_relative() == 0) { - write_traj_label (cv_traj_os); + write_traj_label(cv_traj_os); } if ((cvm::step_absolute() % cv_traj_freq) == 0) { - write_traj (cv_traj_os); + write_traj(cv_traj_os); } if (restart_out_freq) { // flush the trajectory file if we are at the restart frequency if ( (cvm::step_relative() > 0) && ((cvm::step_absolute() % restart_out_freq) == 0) ) { - cvm::log ("Synchronizing (emptying the buffer of) trajectory file \""+ + cvm::log("Synchronizing (emptying the buffer of) trajectory file \""+ cv_traj_name+"\".\n"); cv_traj_os.flush(); } } } // end if (cv_traj_freq) return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } int colvarmodule::analyze() { if (cvm::debug()) { - cvm::log ("colvarmodule::analyze(), step = "+cvm::to_str (it)+".\n"); + cvm::log("colvarmodule::analyze(), step = "+cvm::to_str(it)+".\n"); } if (cvm::step_relative() == 0) - cvm::log ("Performing analysis.\n"); + cvm::log("Performing analysis.\n"); // perform colvar-specific analysis for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { cvm::increase_depth(); (*cvi)->analyse(); cvm::decrease_depth(); } // perform bias-specific analysis for (std::vector::iterator bi = biases.begin(); bi != biases.end(); bi++) { cvm::increase_depth(); (*bi)->analyse(); cvm::decrease_depth(); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } int colvarmodule::setup() { // loop over all components of all colvars to reset masses of all groups for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { (*cvi)->setup(); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } colvarmodule::~colvarmodule() { reset(); delete parse; proxy = NULL; } int colvarmodule::reset() { cvm::log("Resetting the Collective Variables Module.\n"); // Iterate backwards because we are deleting the elements as we go for (std::vector::reverse_iterator cvi = colvars.rbegin(); cvi != colvars.rend(); cvi++) { delete *cvi; // the colvar destructor updates the colvars array } colvars.clear(); // Iterate backwards because we are deleting the elements as we go for (std::vector::reverse_iterator bi = biases.rbegin(); bi != biases.rend(); bi++) { delete *bi; // the bias destructor updates the biases array } biases.clear(); index_groups.clear(); index_group_names.clear(); // Do not close file here, as we might not be done with it yet. cv_traj_os.flush(); return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } int colvarmodule::setup_input() { // name of input state file restart_in_name = proxy->input_prefix().size() ? - std::string (proxy->input_prefix()+".colvars.state") : - std::string ("") ; + std::string(proxy->input_prefix()+".colvars.state") : + std::string("") ; // read the restart configuration, if available if (restart_in_name.size()) { // read the restart file - std::ifstream input_is (restart_in_name.c_str()); + std::ifstream input_is(restart_in_name.c_str()); if (!input_is.good()) { - cvm::error ("Error: in opening restart file \""+ - std::string (restart_in_name)+"\".\n", + cvm::error("Error: in opening restart file \""+ + std::string(restart_in_name)+"\".\n", FILE_ERROR); return COLVARS_ERROR; } else { - cvm::log ("Restarting from file \""+restart_in_name+"\".\n"); - read_restart (input_is); + cvm::log("Restarting from file \""+restart_in_name+"\".\n"); + read_restart(input_is); if (cvm::get_error() != COLVARS_OK) { return COLVARS_ERROR; } - cvm::log (cvm::line_marker); + cvm::log(cvm::line_marker); } } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } int colvarmodule::setup_output() { // output state file (restart) restart_out_name = proxy->restart_output_prefix().size() ? - std::string (proxy->restart_output_prefix()+".colvars.state") : - std::string (""); + std::string(proxy->restart_output_prefix()+".colvars.state") : + std::string(""); if (restart_out_name.size()) { - cvm::log ("The restart output state file will be \""+restart_out_name+"\".\n"); + cvm::log("The restart output state file will be \""+restart_out_name+"\".\n"); } output_prefix = proxy->output_prefix(); if (output_prefix.size()) { - cvm::log ("The final output state file will be \""+ + cvm::log("The final output state file will be \""+ (output_prefix.size() ? - std::string (output_prefix+".colvars.state") : - std::string ("colvars.state"))+"\".\n"); + std::string(output_prefix+".colvars.state") : + std::string("colvars.state"))+"\".\n"); // cvm::log (cvm::line_marker); } cv_traj_name = (output_prefix.size() ? - std::string (output_prefix+".colvars.traj") : - std::string ("")); + std::string(output_prefix+".colvars.traj") : + std::string("")); if (cv_traj_freq && cv_traj_name.size()) { - // open trajectory file - if (cv_traj_append) { - cvm::log ("Appending to colvar trajectory file \""+cv_traj_name+ - "\".\n"); - cv_traj_os.open (cv_traj_name.c_str(), std::ios::app); - } else { - cvm::log ("Writing to colvar trajectory file \""+cv_traj_name+ - "\".\n"); - proxy->backup_file (cv_traj_name.c_str()); - cv_traj_os.open (cv_traj_name.c_str(), std::ios::out); - } - cv_traj_os.setf (std::ios::scientific, std::ios::floatfield); + open_traj_file(cv_traj_name); } - return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); + return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -std::istream & colvarmodule::read_restart (std::istream &is) +std::istream & colvarmodule::read_restart(std::istream &is) { { // read global restart information std::string restart_conf; - if (is >> colvarparse::read_block ("configuration", restart_conf)) { + if (is >> colvarparse::read_block("configuration", restart_conf)) { if (it_restart_from_state_file) { - parse->get_keyval (restart_conf, "step", + parse->get_keyval(restart_conf, "step", it_restart, (size_t) 0, colvarparse::parse_silent); it = it_restart; } } is.clear(); } // colvars restart cvm::increase_depth(); for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { - if ( !((*cvi)->read_restart (is)) ) { - cvm::error ("Error: in reading restart configuration for collective variable \""+ + if ( !((*cvi)->read_restart(is)) ) { + cvm::error("Error: in reading restart configuration for collective variable \""+ (*cvi)->name+"\".\n", INPUT_ERROR); } } // biases restart for (std::vector::iterator bi = biases.begin(); bi != biases.end(); bi++) { - if (!((*bi)->read_restart (is))) - cvm::error ("Error: in reading restart configuration for bias \""+ + if (!((*bi)->read_restart(is))) + cvm::error("Error: in reading restart configuration for bias \""+ (*bi)->name+"\".\n", INPUT_ERROR); } cvm::decrease_depth(); return is; } -int colvarmodule::backup_file (char const *filename) +int colvarmodule::backup_file(char const *filename) { - return proxy->backup_file (filename); + return proxy->backup_file(filename); } int colvarmodule::write_output_files() { // if this is a simulation run (i.e. not a postprocessing), output data // must be written to be able to restart the simulation std::string const out_name = (output_prefix.size() ? - std::string (output_prefix+".colvars.state") : - std::string ("colvars.state")); - cvm::log ("Saving collective variables state to \""+out_name+"\".\n"); - proxy->backup_file (out_name.c_str()); - std::ofstream out (out_name.c_str()); - out.setf (std::ios::scientific, std::ios::floatfield); - this->write_restart (out); + std::string(output_prefix+".colvars.state") : + std::string("colvars.state")); + cvm::log("Saving collective variables state to \""+out_name+"\".\n"); + proxy->backup_file(out_name.c_str()); + std::ofstream out(out_name.c_str()); + out.setf(std::ios::scientific, std::ios::floatfield); + this->write_restart(out); out.close(); cvm::increase_depth(); for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { (*cvi)->write_output_files(); } cvm::decrease_depth(); // do not close to avoid problems with multiple NAMD runs cv_traj_os.flush(); return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -int colvarmodule::read_traj (char const *traj_filename, +int colvarmodule::read_traj(char const *traj_filename, size_t traj_read_begin, size_t traj_read_end) { - cvm::log ("Opening trajectory file \""+ - std::string (traj_filename)+"\".\n"); - std::ifstream traj_is (traj_filename); + cvm::log("Opening trajectory file \""+ + std::string(traj_filename)+"\".\n"); + std::ifstream traj_is(traj_filename); while (true) { while (true) { - std::string line (""); + std::string line(""); do { - if (!colvarparse::getline_nocomments (traj_is, line)) { - cvm::log ("End of file \""+std::string (traj_filename)+ + if (!colvarparse::getline_nocomments(traj_is, line)) { + cvm::log("End of file \""+std::string(traj_filename)+ "\" reached, or corrupted file.\n"); traj_is.close(); return false; } - } while (line.find_first_not_of (colvarparse::white_space) == std::string::npos); + } while (line.find_first_not_of(colvarparse::white_space) == std::string::npos); - std::istringstream is (line); + std::istringstream is(line); if (!(is >> it)) return false; if ( (it < traj_read_begin) ) { if ((it % 1000) == 0) std::cerr << "Skipping trajectory step " << it << " \r"; continue; } else { if ((it % 1000) == 0) std::cerr << "Reading from trajectory, step = " << it << " \r"; if ( (traj_read_end > traj_read_begin) && (it > traj_read_end) ) { std::cerr << "\n"; - cvm::error ("Reached the end of the trajectory, " - "read_end = "+cvm::to_str (traj_read_end)+"\n", + cvm::error("Reached the end of the trajectory, " + "read_end = "+cvm::to_str(traj_read_end)+"\n", FILE_ERROR); return COLVARS_ERROR; } for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { - if (!(*cvi)->read_traj (is)) { - cvm::error ("Error: in reading colvar \""+(*cvi)->name+ + if (!(*cvi)->read_traj(is)) { + cvm::error("Error: in reading colvar \""+(*cvi)->name+ "\" from trajectory file \""+ - std::string (traj_filename)+"\".\n", + std::string(traj_filename)+"\".\n", FILE_ERROR); return COLVARS_ERROR; } } break; } } } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -std::ostream & colvarmodule::write_restart (std::ostream &os) +std::ostream & colvarmodule::write_restart(std::ostream &os) { - os.setf (std::ios::scientific, std::ios::floatfield); + os.setf(std::ios::scientific, std::ios::floatfield); os << "configuration {\n" - << " step " << std::setw (it_width) + << " step " << std::setw(it_width) << it << "\n" << " dt " << dt() << "\n" << "}\n\n"; cvm::increase_depth(); for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { - (*cvi)->write_restart (os); + (*cvi)->write_restart(os); } for (std::vector::iterator bi = biases.begin(); bi != biases.end(); bi++) { - (*bi)->write_restart (os); + (*bi)->write_restart(os); } cvm::decrease_depth(); return os; } -int colvarmodule::open_traj_file (std::string const &file_name) +int colvarmodule::open_traj_file(std::string const &file_name) { + if (cv_traj_os.is_open()) { + return COLVARS_OK; + } + // (re)open trajectory file if (cv_traj_append) { - cvm::log ("Appending to colvar trajectory file \""+file_name+ + cvm::log("Appending to colvar trajectory file \""+file_name+ "\".\n"); - cv_traj_os.open (file_name.c_str(), std::ios::app); + cv_traj_os.open(file_name.c_str(), std::ios::app); } else { - cvm::log ("Overwriting colvar trajectory file \""+file_name+ + cvm::log("Writing to colvar trajectory file \""+file_name+ "\".\n"); - proxy->backup_file (file_name.c_str()); - cv_traj_os.open (file_name.c_str(), std::ios::out); + proxy->backup_file(file_name.c_str()); + cv_traj_os.open(file_name.c_str(), std::ios::out); } - if (!cv_traj_os.good()) { - cvm::error ("Error: cannot write to file \""+file_name+"\".\n", + + if (!cv_traj_os.is_open()) { + cvm::error("Error: cannot write to file \""+file_name+"\".\n", FILE_ERROR); } + return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } int colvarmodule::close_traj_file() { if (cv_traj_os.good()) { cv_traj_os.close(); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -std::ostream & colvarmodule::write_traj_label (std::ostream &os) +std::ostream & colvarmodule::write_traj_label(std::ostream &os) { if (!os.good()) { cvm::error("Cannot write to trajectory file."); return os; } - os.setf (std::ios::scientific, std::ios::floatfield); + os.setf(std::ios::scientific, std::ios::floatfield); - os << "# " << cvm::wrap_string ("step", cvm::it_width-2) + os << "# " << cvm::wrap_string("step", cvm::it_width-2) << " "; cvm::increase_depth(); for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { - (*cvi)->write_traj_label (os); + (*cvi)->write_traj_label(os); } for (std::vector::iterator bi = biases.begin(); bi != biases.end(); bi++) { - (*bi)->write_traj_label (os); + (*bi)->write_traj_label(os); } os << "\n"; if (cvm::debug()) os.flush(); cvm::decrease_depth(); return os; } -std::ostream & colvarmodule::write_traj (std::ostream &os) +std::ostream & colvarmodule::write_traj(std::ostream &os) { - os.setf (std::ios::scientific, std::ios::floatfield); + os.setf(std::ios::scientific, std::ios::floatfield); - os << std::setw (cvm::it_width) << it + os << std::setw(cvm::it_width) << it << " "; cvm::increase_depth(); for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { - (*cvi)->write_traj (os); + (*cvi)->write_traj(os); } for (std::vector::iterator bi = biases.begin(); bi != biases.end(); bi++) { - (*bi)->write_traj (os); + (*bi)->write_traj(os); } os << "\n"; if (cvm::debug()) os.flush(); cvm::decrease_depth(); return os; } -void cvm::log (std::string const &message) +void cvm::log(std::string const &message) { if (depth > 0) - proxy->log ((std::string (2*depth, ' '))+message); + proxy->log((std::string(2*depth, ' '))+message); else - proxy->log (message); + proxy->log(message); } void cvm::increase_depth() { depth++; } void cvm::decrease_depth() { if (depth) depth--; } -void cvm::error (std::string const &message, int code) +void cvm::error(std::string const &message, int code) { set_error_bits(code); - proxy->error (message); + proxy->error(message); } -void cvm::fatal_error (std::string const &message) +void cvm::fatal_error(std::string const &message) { set_error_bits(FATAL_ERROR); - proxy->fatal_error (message); + proxy->fatal_error(message); } -void cvm::exit (std::string const &message) +void cvm::exit(std::string const &message) { - proxy->exit (message); + proxy->exit(message); } -int cvm::read_index_file (char const *filename) +int cvm::read_index_file(char const *filename) { - std::ifstream is (filename, std::ios::binary); + std::ifstream is(filename, std::ios::binary); if (!is.good()) - cvm::error ("Error: in opening index file \""+ - std::string (filename)+"\".\n", + cvm::error("Error: in opening index file \""+ + std::string(filename)+"\".\n", FILE_ERROR); while (is.good()) { char open, close; std::string group_name; if ( (is >> open) && (open == '[') && (is >> group_name) && (is >> close) && (close == ']') ) { for (std::list::iterator names_i = index_group_names.begin(); names_i != index_group_names.end(); names_i++) { if (*names_i == group_name) { - cvm::error ("Error: the group name \""+group_name+ + cvm::error("Error: the group name \""+group_name+ "\" appears in multiple index files.\n", FILE_ERROR); } } - cvm::index_group_names.push_back (group_name); - cvm::index_groups.push_back (std::vector ()); + cvm::index_group_names.push_back(group_name); + cvm::index_groups.push_back(std::vector ()); } else { - cvm::error ("Error: in parsing index file \""+ - std::string (filename)+"\".\n", + cvm::error("Error: in parsing index file \""+ + std::string(filename)+"\".\n", INPUT_ERROR); } int atom_number = 1; size_t pos = is.tellg(); while ( (is >> atom_number) && (atom_number > 0) ) { - (cvm::index_groups.back()).push_back (atom_number); + (cvm::index_groups.back()).push_back(atom_number); pos = is.tellg(); } is.clear(); - is.seekg (pos, std::ios::beg); + is.seekg(pos, std::ios::beg); std::string delim; if ( (is >> delim) && (delim == "[") ) { // new group is.clear(); - is.seekg (pos, std::ios::beg); + is.seekg(pos, std::ios::beg); } else { break; } } - cvm::log ("The following index groups were read from the index file \""+ - std::string (filename)+"\":\n"); + cvm::log("The following index groups were read from the index file \""+ + std::string(filename)+"\":\n"); std::list::iterator names_i = index_group_names.begin(); std::list >::iterator lists_i = index_groups.begin(); for ( ; names_i != index_group_names.end() ; names_i++, lists_i++) { - cvm::log (" "+(*names_i)+" ("+cvm::to_str (lists_i->size())+" atoms).\n"); + cvm::log(" "+(*names_i)+" ("+cvm::to_str(lists_i->size())+" atoms).\n"); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } -int cvm::load_atoms (char const *file_name, +int cvm::load_atoms(char const *file_name, std::vector &atoms, std::string const &pdb_field, double const pdb_field_value) { - return proxy->load_atoms (file_name, atoms, pdb_field, pdb_field_value); + return proxy->load_atoms(file_name, atoms, pdb_field, pdb_field_value); } -int cvm::load_coords (char const *file_name, +int cvm::load_coords(char const *file_name, std::vector &pos, const std::vector &indices, std::string const &pdb_field, double const pdb_field_value) { // Differentiate between PDB and XYZ files // for XYZ files, use CVM internal parser // otherwise call proxy function for PDB - std::string const ext (strlen(file_name) > 4 ? (file_name + (strlen(file_name) - 4)) : file_name); - if (colvarparse::to_lower_cppstr (ext) == std::string (".xyz")) { + std::string const ext(strlen(file_name) > 4 ? (file_name + (strlen(file_name) - 4)) : file_name); + if (colvarparse::to_lower_cppstr(ext) == std::string(".xyz")) { if ( pdb_field.size() > 0 ) { cvm::error("Error: PDB column may not be specified for XYZ coordinate file.\n", INPUT_ERROR); return COLVARS_ERROR; } - return cvm::load_coords_xyz (file_name, pos, indices); + return cvm::load_coords_xyz(file_name, pos, indices); } else { - return proxy->load_coords (file_name, pos, indices, pdb_field, pdb_field_value); + return proxy->load_coords(file_name, pos, indices, pdb_field, pdb_field_value); } } -int cvm::load_coords_xyz (char const *filename, +int cvm::load_coords_xyz(char const *filename, std::vector &pos, const std::vector &indices) { - std::ifstream xyz_is (filename); + std::ifstream xyz_is(filename); unsigned int natoms; char symbol[256]; std::string line; if ( ! (xyz_is >> natoms) ) { - cvm::error ("Error: cannot parse XYZ file " - + std::string (filename) + ".\n", INPUT_ERROR); + cvm::error("Error: cannot parse XYZ file " + + std::string(filename) + ".\n", INPUT_ERROR); } // skip comment line - std::getline (xyz_is, line); - std::getline (xyz_is, line); - xyz_is.width (255); + std::getline(xyz_is, line); + std::getline(xyz_is, line); + xyz_is.width(255); std::vector::iterator pos_i = pos.begin(); if (pos.size() != natoms) { // Use specified indices int next = 0; // indices are zero-based std::vector::const_iterator index = indices.begin(); for ( ; pos_i != pos.end() ; pos_i++, index++) { while ( next < *index ) { - std::getline (xyz_is, line); + std::getline(xyz_is, line); next++; } xyz_is >> symbol; xyz_is >> (*pos_i)[0] >> (*pos_i)[1] >> (*pos_i)[2]; } } else { // Use all positions for ( ; pos_i != pos.end() ; pos_i++) { xyz_is >> symbol; xyz_is >> (*pos_i)[0] >> (*pos_i)[1] >> (*pos_i)[2]; } } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } // static pointers std::vector colvarmodule::colvars; std::vector colvarmodule::biases; size_t colvarmodule::n_abf_biases = 0; size_t colvarmodule::n_rest_biases = 0; size_t colvarmodule::n_histo_biases = 0; size_t colvarmodule::n_meta_biases = 0; colvarproxy *colvarmodule::proxy = NULL; // static runtime data cvm::real colvarmodule::debug_gradients_step_size = 1.0e-03; int colvarmodule::errorCode = 0; size_t colvarmodule::it = 0; size_t colvarmodule::it_restart = 0; size_t colvarmodule::restart_out_freq = 0; size_t colvarmodule::cv_traj_freq = 0; size_t colvarmodule::depth = 0; bool colvarmodule::b_analysis = false; cvm::real colvarmodule::rotation::crossing_threshold = 1.0E-04; std::list colvarmodule::index_group_names; std::list > colvarmodule::index_groups; - +bool colvarmodule::use_scripted_forces = false; // file name prefixes std::string colvarmodule::output_prefix = ""; std::string colvarmodule::restart_in_name = ""; // i/o constants size_t const colvarmodule::it_width = 12; size_t const colvarmodule::cv_prec = 14; size_t const colvarmodule::cv_width = 21; size_t const colvarmodule::en_prec = 14; size_t const colvarmodule::en_width = 21; std::string const colvarmodule::line_marker = "----------------------------------------------------------------------\n"; diff --git a/lib/colvars/colvarmodule.h b/lib/colvars/colvarmodule.h index ba1a4937e..3c78d9c60 100644 --- a/lib/colvars/colvarmodule.h +++ b/lib/colvars/colvarmodule.h @@ -1,612 +1,614 @@ /// -*- c++ -*- #ifndef COLVARMODULE_H #define COLVARMODULE_H #ifndef COLVARS_VERSION -#define COLVARS_VERSION "2014-10-21" +#define COLVARS_VERSION "2014-11-21" #endif #ifndef COLVARS_DEBUG #define COLVARS_DEBUG false #endif /// \file colvarmodule.h /// \brief Collective variables main module /// /// This file declares the main class for defining and manipulating /// collective variables: there should be only one instance of this /// class, because several variables are made static (i.e. they are /// shared between all object instances) to be accessed from other /// objects. // Internal method return codes +#define COLVARS_NOT_IMPLEMENTED -2 #define COLVARS_ERROR -1 #define COLVARS_OK 0 // On error, values of the colvars module error register #define GENERAL_ERROR 1 #define FILE_ERROR (1<<1) #define MEMORY_ERROR (1<<2) #define BUG_ERROR (1<<3) // Inconsistent state indicating bug #define INPUT_ERROR (1<<4) // out of bounds or inconsistent input #define DELETE_COLVARS (1<<5) // Instruct the caller to delete cvm #define FATAL_ERROR (1<<6) // Should be set, or not, together with other bits #include #include #include #include #include #include #include #include #include class colvarparse; class colvar; class colvarbias; class colvarproxy; class colvarscript; /// \brief Collective variables module (main class) /// /// Class to control the collective variables calculation. An object /// (usually one) of this class is spawned from the MD program, /// containing all i/o routines and general interface. /// /// At initialization, the colvarmodule object creates a proxy object /// to provide a transparent interface between the MD program and the /// child objects class colvarmodule { private: /// Impossible to initialize the main object without arguments colvarmodule(); public: friend class colvarproxy; // TODO colvarscript should be unaware of colvarmodule's internals friend class colvarscript; /// Defining an abstract real number allows to switch precision typedef double real; /// Residue identifier typedef int residue_id; class rvector; - template class vector1d; - template class matrix2d; + template class vector1d; + template class matrix2d; class quaternion; class rotation; /// \brief Atom position (different type name from rvector, to make /// possible future PBC-transparent implementations) typedef rvector atom_pos; /// \brief 3x3 matrix of real numbers class rmatrix; // allow these classes to access protected data class atom; class atom_group; friend class atom; friend class atom_group; typedef std::vector::iterator atom_iter; typedef std::vector::const_iterator atom_const_iter; /// Module-wide error state /// see constants at the top of this file static int errorCode; static inline void set_error_bits(int code) { errorCode |= code; } static inline int get_error() { return errorCode; } static inline void clear_error() { errorCode = 0; } /// Current step number static size_t it; /// Starting step number for this run static size_t it_restart; /// Return the current step number from the beginning of this run static inline size_t step_relative() { return it - it_restart; } /// Return the current step number from the beginning of the whole /// calculation static inline size_t step_absolute() { return it; } /// If true, get it_restart from the state file; if set to false, /// the MD program is providing it bool it_restart_from_state_file; /// \brief Finite difference step size (if there is no dynamics, or /// if gradients need to be tested independently from the size of /// dt) static real debug_gradients_step_size; /// Prefix for all output files for this run static std::string output_prefix; /// input restart file name (determined from input_prefix) static std::string restart_in_name; /// Array of collective variables static std::vector colvars; /* TODO: implement named CVCs /// Array of named (reusable) collective variable components static std::vector cvcs; /// Named cvcs register themselves at initialization time - inline void register_cvc (cvc *p) { + inline void register_cvc(cvc *p) { cvcs.push_back(p); } */ /// Array of collective variable biases static std::vector biases; /// \brief Number of ABF biases initialized (in normal conditions /// should be 1) static size_t n_abf_biases; /// \brief Number of metadynamics biases initialized (in normal /// conditions should be 1) static size_t n_meta_biases; /// \brief Number of restraint biases initialized (no limit on the /// number) static size_t n_rest_biases; /// \brief Number of histograms initialized (no limit on the /// number) static size_t n_histo_biases; /// \brief Whether debug output should be enabled (compile-time option) static inline bool debug() { return COLVARS_DEBUG; } /// \brief Constructor \param config_name Configuration file name /// \param restart_name (optional) Restart file name - colvarmodule (colvarproxy *proxy); + colvarmodule(colvarproxy *proxy); /// Destructor ~colvarmodule(); /// Actual function called by the destructor int reset(); /// Open a config file, load its contents, and pass it to config_string() - int config_file (char const *config_file_name); + int config_file(char const *config_file_name); /// \brief Parse a config string assuming it is a complete configuration /// (i.e. calling all parse functions) - int config_string (std::string const &conf); + int config_string(std::string const &conf); /// \brief Parse a "clean" config string (no comments) - int config (std::string &conf); + int config(std::string &conf); // Parse functions (setup internal data based on a string) /// Parse the few module's global parameters - int parse_global_params (std::string const &conf); + int parse_global_params(std::string const &conf); /// Parse and initialize collective variables - int parse_colvars (std::string const &conf); + int parse_colvars(std::string const &conf); /// Parse and initialize collective variable biases - int parse_biases (std::string const &conf); + int parse_biases(std::string const &conf); + + /// Parse and initialize collective variable biases of a specific type + template + int parse_biases_type(std::string const &conf, char const *keyword, size_t &bias_count); /// 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) // No additional parsing is done within these functions /// (Re)initialize internal data (currently used by LAMMPS) /// Also calls setup() member functions of colvars and biases int setup(); /// (Re)initialize and (re)read the input state file calling read_restart() int setup_input(); /// (Re)initialize the output trajectory and state file (does not write it yet) int setup_output(); /// Read the input restart file - std::istream & read_restart (std::istream &is); + std::istream & read_restart(std::istream &is); /// Write the output restart file - std::ostream & write_restart (std::ostream &os); + std::ostream & write_restart(std::ostream &os); /// Open a trajectory file if requested (and leave it open) - int open_traj_file (std::string const &file_name); + int open_traj_file(std::string const &file_name); /// Close it int close_traj_file(); /// Write in the trajectory file - std::ostream & write_traj (std::ostream &os); + std::ostream & write_traj(std::ostream &os); /// Write explanatory labels in the trajectory file - std::ostream & write_traj_label (std::ostream &os); + std::ostream & write_traj_label(std::ostream &os); /// Write all FINAL output files int write_output_files(); /// Backup a file before writing it - static int backup_file (char const *filename); + static int backup_file(char const *filename); /// Look up a bias by name; returns NULL if not found static colvarbias * bias_by_name(std::string const &name); /// Look up a colvar by name; returns NULL if not found static colvar * colvar_by_name(std::string const &name); /// Load new configuration for the given bias - /// currently works for harmonic (force constant and/or centers) - int change_configuration (std::string const &bias_name, std::string const &conf); + int change_configuration(std::string const &bias_name, std::string const &conf); /// Read a colvar value std::string read_colvar(std::string const &name); /// Calculate change in energy from using alt. config. for the given bias - /// currently works for harmonic (force constant and/or centers) - real energy_difference (std::string const &bias_name, std::string const &conf); + 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); + int 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); + int 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); + int bias_bin_count(std::string const &bias_name, size_t bin_index); //// Share among replicas. - void bias_share(std::string const &bias_name); + int bias_share(std::string const &bias_name); /// Calculate collective variables and biases int calc(); /// Perform analysis int analyze(); /// \brief Read a collective variable trajectory (post-processing /// only, not called at runtime) - int read_traj (char const *traj_filename, + int read_traj(char const *traj_filename, size_t traj_read_begin, size_t traj_read_end); /// Quick conversion of an object to a string - template static std::string to_str (T const &x, + template static std::string to_str(T const &x, size_t const &width = 0, size_t const &prec = 0); /// Quick conversion of a vector of objects to a string - template static std::string to_str (std::vector const &x, + template static std::string to_str(std::vector const &x, size_t const &width = 0, size_t const &prec = 0); /// Reduce the number of characters in a string - static inline std::string wrap_string (std::string const &s, + static inline std::string wrap_string(std::string const &s, size_t const &nchars) { if (!s.size()) - return std::string (nchars, ' '); + return std::string(nchars, ' '); else - return ( (s.size() <= size_t (nchars)) ? - (s+std::string (nchars-s.size(), ' ')) : - (std::string (s, 0, nchars)) ); + return ( (s.size() <= size_t(nchars)) ? + (s+std::string(nchars-s.size(), ' ')) : + (std::string(s, 0, nchars)) ); } /// Number of characters to represent a time step static size_t const it_width; /// Number of digits to represent a collective variables value(s) static size_t const cv_prec; /// Number of characters to represent a collective variables value(s) static size_t const cv_width; /// Number of digits to represent the collective variables energy static size_t const en_prec; /// Number of characters to represent the collective variables energy static size_t const en_width; /// Line separator in the log output static std::string const line_marker; // proxy functions /// \brief Value of the unit for atomic coordinates with respect to /// angstroms (used by some variables for hard-coded default values) static real unit_angstrom(); /// \brief Boltmann constant static real boltzmann(); /// \brief Temperature of the simulation (K) static real temperature(); /// \brief Time step of MD integrator (fs) static real dt(); /// Request calculation of system force from MD engine static void request_system_force(); /// Print a message to the main log - static void log (std::string const &message); + static void log(std::string const &message); /// Print a message to the main log and exit with error code - static void fatal_error (std::string const &message); + static void fatal_error(std::string const &message); /// Print a message to the main log and set global error code - static void error (std::string const &message, int code = GENERAL_ERROR); + static void error(std::string const &message, int code = GENERAL_ERROR); /// Print a message to the main log and exit normally - static void exit (std::string const &message); + 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 - static rvector position_distance (atom_pos const &pos1, + static rvector position_distance(atom_pos const &pos1, atom_pos const &pos2); /// \brief Get the square distance between two positions (with /// periodic boundary conditions handled transparently) /// /// Note: in the case of periodic boundary conditions, this provides /// an analytical square distance (while taking the square of /// position_distance() would produce leads to a cusp) - static real position_dist2 (atom_pos const &pos1, + static real position_dist2(atom_pos const &pos1, atom_pos const &pos2); /// \brief Get the closest periodic image to a reference position /// \param pos The position to look for the closest periodic image /// \param ref_pos (optional) The reference position - static void select_closest_image (atom_pos &pos, + static void select_closest_image(atom_pos &pos, atom_pos const &ref_pos); /// \brief Perform select_closest_image() on a set of atomic positions /// /// After that, distance vectors can then be calculated directly, /// without using position_distance() - static void select_closest_images (std::vector &pos, + static void select_closest_images(std::vector &pos, atom_pos const &ref_pos); /// \brief Names of groups from a Gromacs .ndx file to be read at startup static std::list index_group_names; /// \brief Groups from a Gromacs .ndx file read at startup static std::list > index_groups; /// \brief Read a Gromacs .ndx file - static int read_index_file (char const *filename); + static int read_index_file(char const *filename); /// \brief Create atoms from a file \param filename name of the file /// (usually a PDB) \param atoms array of the atoms to be allocated /// \param pdb_field (optiona) if "filename" is a PDB file, use this /// field to determine which are the atoms to be set - static int load_atoms (char const *filename, + static int load_atoms(char const *filename, std::vector &atoms, std::string const &pdb_field, double const pdb_field_value = 0.0); /// \brief Load the coordinates for a group of atoms from a file /// (PDB or XYZ) - static int load_coords (char const *filename, + static int load_coords(char const *filename, std::vector &pos, const std::vector &indices, std::string const &pdb_field, double const pdb_field_value = 0.0); /// \brief Load the coordinates for a group of atoms from an /// XYZ file - static int load_coords_xyz (char const *filename, + static int load_coords_xyz(char const *filename, std::vector &pos, const std::vector &indices); /// Frequency for collective variables trajectory output static size_t cv_traj_freq; /// \brief True if only analysis is performed and not a run static bool b_analysis; /// Frequency for saving output restarts static size_t restart_out_freq; /// Output restart file name std::string restart_out_name; /// Pseudo-random number with Gaussian distribution - static real rand_gaussian (void); + static real rand_gaussian(void); protected: /// Configuration file std::ifstream config_s; /// Configuration file parser object colvarparse *parse; /// Name of the trajectory file std::string cv_traj_name; /// Collective variables output trajectory file std::ofstream cv_traj_os; /// Appending to the existing trajectory file? bool cv_traj_append; /// Output restart file std::ofstream restart_out_os; /// \brief Counter for the current depth in the object hierarchy (useg e.g. in output static size_t depth; /// Use scripted colvars forces? - bool use_scripted_forces; + static bool use_scripted_forces; public: /// \brief Pointer to the proxy object, used to retrieve atomic data /// from the hosting program; it is static in order to be accessible /// from static functions in the colvarmodule class static colvarproxy *proxy; /// Increase the depth (number of indentations in the output) static void increase_depth(); /// Decrease the depth (number of indentations in the output) static void decrease_depth(); + + static inline bool scripted_forces() { return use_scripted_forces; } }; /// Shorthand for the frequently used type prefix typedef colvarmodule cvm; #include "colvartypes.h" std::ostream & operator << (std::ostream &os, cvm::rvector const &v); std::istream & operator >> (std::istream &is, cvm::rvector &v); -template std::string cvm::to_str (T const &x, +template std::string cvm::to_str(T const &x, size_t const &width, size_t const &prec) { std::ostringstream os; - if (width) os.width (width); + if (width) os.width(width); if (prec) { - os.setf (std::ios::scientific, std::ios::floatfield); - os.precision (prec); + os.setf(std::ios::scientific, std::ios::floatfield); + os.precision(prec); } os << x; return os.str(); } -template std::string cvm::to_str (std::vector const &x, +template std::string cvm::to_str(std::vector const &x, size_t const &width, size_t const &prec) { - if (!x.size()) return std::string (""); + if (!x.size()) return std::string(""); std::ostringstream os; if (prec) { - os.setf (std::ios::scientific, std::ios::floatfield); + os.setf(std::ios::scientific, std::ios::floatfield); } os << "{ "; - if (width) os.width (width); - if (prec) os.precision (prec); + if (width) os.width(width); + if (prec) os.precision(prec); os << x[0]; for (size_t i = 1; i < x.size(); i++) { os << ", "; - if (width) os.width (width); - if (prec) os.precision (prec); + if (width) os.width(width); + if (prec) os.precision(prec); os << x[i]; } os << " }"; return os.str(); } #include "colvarproxy.h" inline cvm::real cvm::unit_angstrom() { return proxy->unit_angstrom(); } inline cvm::real cvm::boltzmann() { return proxy->boltzmann(); } inline cvm::real cvm::temperature() { return proxy->temperature(); } 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); + proxy->request_system_force(true); } -inline void cvm::select_closest_image (atom_pos &pos, +inline void cvm::select_closest_image(atom_pos &pos, atom_pos const &ref_pos) { - proxy->select_closest_image (pos, ref_pos); + proxy->select_closest_image(pos, ref_pos); } -inline void cvm::select_closest_images (std::vector &pos, +inline void cvm::select_closest_images(std::vector &pos, atom_pos const &ref_pos) { - proxy->select_closest_images (pos, ref_pos); + proxy->select_closest_images(pos, ref_pos); } -inline cvm::rvector cvm::position_distance (atom_pos const &pos1, +inline cvm::rvector cvm::position_distance(atom_pos const &pos1, atom_pos const &pos2) { - return proxy->position_distance (pos1, pos2); + return proxy->position_distance(pos1, pos2); } -inline cvm::real cvm::position_dist2 (cvm::atom_pos const &pos1, +inline cvm::real cvm::position_dist2(cvm::atom_pos const &pos1, cvm::atom_pos const &pos2) { - return proxy->position_dist2 (pos1, pos2); + return proxy->position_dist2(pos1, pos2); } -inline cvm::real cvm::rand_gaussian (void) +inline cvm::real cvm::rand_gaussian(void) { return proxy->rand_gaussian(); } #endif diff --git a/lib/colvars/colvarparse.cpp b/lib/colvars/colvarparse.cpp index 486a8f01a..291c0108e 100644 --- a/lib/colvars/colvarparse.cpp +++ b/lib/colvars/colvarparse.cpp @@ -1,642 +1,642 @@ /// -*- c++ -*- #include #include #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" // space & tab std::string const colvarparse::white_space = " \t"; std::string colvarparse::dummy_string = ""; size_t colvarparse::dummy_pos = 0; // definition of single-value keyword parsers #define _get_keyval_scalar_string_(TYPE) \ \ - bool colvarparse::get_keyval (std::string const &conf, \ - char const *key, \ - TYPE &value, \ - TYPE const &def_value, \ - Parse_Mode const parse_mode) \ + bool colvarparse::get_keyval(std::string const &conf, \ + char const *key, \ + TYPE &value, \ + TYPE const &def_value, \ + Parse_Mode const parse_mode) \ { \ std::string data; \ bool b_found = false, b_found_any = false; \ size_t save_pos = 0, found_count = 0; \ \ do { \ std::string data_this = ""; \ - b_found = key_lookup (conf, key, data_this, save_pos); \ + b_found = key_lookup(conf, key, data_this, save_pos); \ if (b_found) { \ if (!b_found_any) \ b_found_any = true; \ found_count++; \ data = data_this; \ } \ } while (b_found); \ \ if (found_count > 1) \ - cvm::log ("Warning: found more than one instance of \""+ \ - std::string (key)+"\".\n"); \ + cvm::log("Warning: found more than one instance of \""+ \ + std::string(key)+"\".\n"); \ \ if (data.size()) { \ - std::istringstream is (data); \ - TYPE x (def_value); \ + std::istringstream is(data); \ + TYPE x(def_value); \ if (is >> x) \ value = x; \ else \ - cvm::error ("Error: in parsing \""+ \ - std::string (key)+"\".\n", INPUT_ERROR); \ + cvm::error("Error: in parsing \""+ \ + std::string(key)+"\".\n", INPUT_ERROR); \ if (parse_mode != parse_silent) { \ - cvm::log ("# "+std::string (key)+" = "+ \ - cvm::to_str (value)+"\n"); \ + cvm::log("# "+std::string(key)+" = "+ \ + cvm::to_str(value)+"\n"); \ } \ } else { \ \ if (b_found_any) \ - cvm::error ("Error: improper or missing value " \ - "for \""+std::string (key)+"\".\n", INPUT_ERROR); \ + cvm::error("Error: improper or missing value " \ + "for \""+std::string(key)+"\".\n", INPUT_ERROR); \ value = def_value; \ if (parse_mode != parse_silent) { \ - cvm::log ("# "+std::string (key)+" = \""+ \ - cvm::to_str (def_value)+"\" [default]\n"); \ + cvm::log("# "+std::string(key)+" = \""+ \ + cvm::to_str(def_value)+"\" [default]\n"); \ } \ } \ \ return b_found_any; \ } #define _get_keyval_scalar_(TYPE) \ \ - bool colvarparse::get_keyval (std::string const &conf, \ - char const *key, \ - TYPE &value, \ - TYPE const &def_value, \ - Parse_Mode const parse_mode) \ + bool colvarparse::get_keyval(std::string const &conf, \ + char const *key, \ + TYPE &value, \ + TYPE const &def_value, \ + Parse_Mode const parse_mode) \ { \ std::string data; \ bool b_found = false, b_found_any = false; \ size_t save_pos = 0, found_count = 0; \ \ do { \ std::string data_this = ""; \ - b_found = key_lookup (conf, key, data_this, save_pos); \ + b_found = key_lookup(conf, key, data_this, save_pos); \ if (b_found) { \ if (!b_found_any) \ b_found_any = true; \ found_count++; \ data = data_this; \ } \ } while (b_found); \ \ if (found_count > 1) \ - cvm::log ("Warning: found more than one instance of \""+ \ - std::string (key)+"\".\n"); \ + cvm::log("Warning: found more than one instance of \""+ \ + std::string(key)+"\".\n"); \ \ if (data.size()) { \ - std::istringstream is (data); \ + std::istringstream is(data); \ size_t data_count = 0; \ - TYPE x (def_value); \ + TYPE x(def_value); \ while (is >> x) { \ value = x; \ data_count++; \ } \ if (data_count == 0) \ - cvm::fatal_error ("Error: in parsing \""+ \ - std::string (key)+"\".\n"); \ + cvm::fatal_error("Error: in parsing \""+ \ + std::string(key)+"\".\n"); \ if (data_count > 1) \ - cvm::error ("Error: multiple values " \ - "are not allowed for keyword \""+ \ - std::string (key)+"\".\n", INPUT_ERROR); \ + cvm::error("Error: multiple values " \ + "are not allowed for keyword \""+ \ + std::string(key)+"\".\n", INPUT_ERROR); \ if (parse_mode != parse_silent) { \ - cvm::log ("# "+std::string (key)+" = "+ \ - cvm::to_str (value)+"\n"); \ + cvm::log("# "+std::string(key)+" = "+ \ + cvm::to_str(value)+"\n"); \ } \ } else { \ \ if (b_found_any) \ - cvm::error ("Error: improper or missing value " \ - "for \""+std::string (key)+"\".\n", INPUT_ERROR); \ + cvm::error("Error: improper or missing value " \ + "for \""+std::string(key)+"\".\n", INPUT_ERROR); \ value = def_value; \ if (parse_mode != parse_silent) { \ - cvm::log ("# "+std::string (key)+" = "+ \ - cvm::to_str (def_value)+" [default]\n"); \ + cvm::log("# "+std::string(key)+" = "+ \ + cvm::to_str(def_value)+" [default]\n"); \ } \ } \ \ return b_found_any; \ } // definition of multiple-value keyword parsers #define _get_keyval_vector_(TYPE) \ \ - bool colvarparse::get_keyval (std::string const &conf, \ - char const *key, \ - std::vector &values, \ - std::vector const &def_values, \ - Parse_Mode const parse_mode) \ + bool colvarparse::get_keyval(std::string const &conf, \ + char const *key, \ + std::vector &values, \ + std::vector const &def_values, \ + Parse_Mode const parse_mode) \ { \ std::string data; \ bool b_found = false, b_found_any = false; \ size_t save_pos = 0, found_count = 0; \ \ do { \ std::string data_this = ""; \ - b_found = key_lookup (conf, key, data_this, save_pos); \ + b_found = key_lookup(conf, key, data_this, save_pos); \ if (b_found) { \ if (!b_found_any) \ b_found_any = true; \ found_count++; \ data = data_this; \ } \ } while (b_found); \ \ if (found_count > 1) \ - cvm::log ("Warning: found more than one instance of \""+ \ - std::string (key)+"\".\n"); \ + cvm::log("Warning: found more than one instance of \""+ \ + std::string(key)+"\".\n"); \ \ if (data.size()) { \ - std::istringstream is (data); \ + std::istringstream is(data); \ \ if (values.size() == 0) { \ \ std::vector x; \ if (def_values.size()) \ x = def_values; \ else \ - x.assign (1, TYPE()); \ + x.assign(1, TYPE()); \ \ for (size_t i = 0; \ ( is >> x[ ((i> x) \ values[i] = x; \ else \ - cvm::error ("Error: in parsing \""+ \ - std::string (key)+"\".\n", INPUT_ERROR); \ + cvm::error("Error: in parsing \""+ \ + std::string(key)+"\".\n", INPUT_ERROR); \ } \ } \ \ if (parse_mode != parse_silent) { \ - cvm::log ("# "+std::string (key)+" = "+ \ - cvm::to_str (values)+"\n"); \ + cvm::log("# "+std::string(key)+" = "+ \ + cvm::to_str(values)+"\n"); \ } \ \ } else { \ \ if (b_found_any) \ - cvm::error ("Error: improper or missing values for \""+ \ - std::string (key)+"\".\n", INPUT_ERROR); \ + cvm::error("Error: improper or missing values for \""+ \ + std::string(key)+"\".\n", INPUT_ERROR); \ \ for (size_t i = 0; i < values.size(); i++) \ values[i] = def_values[ (i > def_values.size()) ? 0 : i ]; \ \ if (parse_mode != parse_silent) { \ - cvm::log ("# "+std::string (key)+" = "+ \ - cvm::to_str (def_values)+" [default]\n"); \ + cvm::log("# "+std::string(key)+" = "+ \ + cvm::to_str(def_values)+" [default]\n"); \ } \ } \ \ return b_found_any; \ } // single-value keyword parsers -_get_keyval_scalar_ (int); -_get_keyval_scalar_ (size_t); -_get_keyval_scalar_string_ (std::string); -_get_keyval_scalar_ (cvm::real); -_get_keyval_scalar_ (cvm::rvector); -_get_keyval_scalar_ (cvm::quaternion); -_get_keyval_scalar_ (colvarvalue); +_get_keyval_scalar_(int); +_get_keyval_scalar_(size_t); +_get_keyval_scalar_string_(std::string); +_get_keyval_scalar_(cvm::real); +_get_keyval_scalar_(cvm::rvector); +_get_keyval_scalar_(cvm::quaternion); +_get_keyval_scalar_(colvarvalue); // multiple-value keyword parsers -_get_keyval_vector_ (int); -_get_keyval_vector_ (size_t); -_get_keyval_vector_ (std::string); -_get_keyval_vector_ (cvm::real); -_get_keyval_vector_ (cvm::rvector); -_get_keyval_vector_ (cvm::quaternion); -_get_keyval_vector_ (colvarvalue); +_get_keyval_vector_(int); +_get_keyval_vector_(size_t); +_get_keyval_vector_(std::string); +_get_keyval_vector_(cvm::real); +_get_keyval_vector_(cvm::rvector); +_get_keyval_vector_(cvm::quaternion); +_get_keyval_vector_(colvarvalue); -bool colvarparse::get_keyval (std::string const &conf, - char const *key, - bool &value, - bool const &def_value, - Parse_Mode const parse_mode) +bool colvarparse::get_keyval(std::string const &conf, + char const *key, + bool &value, + bool const &def_value, + Parse_Mode const parse_mode) { std::string data; bool b_found = false, b_found_any = false; size_t save_pos = 0, found_count = 0; do { std::string data_this = ""; - b_found = key_lookup (conf, key, data_this, save_pos); + b_found = key_lookup(conf, key, data_this, save_pos); if (b_found) { if (!b_found_any) b_found_any = true; found_count++; data = data_this; } } while (b_found); if (found_count > 1) - cvm::log ("Warning: found more than one instance of \""+ - std::string (key)+"\".\n"); + cvm::log("Warning: found more than one instance of \""+ + std::string(key)+"\".\n"); if (data.size()) { - if ( (data == std::string ("on")) || - (data == std::string ("yes")) || - (data == std::string ("true")) ) { + if ( (data == std::string("on")) || + (data == std::string("yes")) || + (data == std::string("true")) ) { value = true; - } else if ( (data == std::string ("off")) || - (data == std::string ("no")) || - (data == std::string ("false")) ) { + } else if ( (data == std::string("off")) || + (data == std::string("no")) || + (data == std::string("false")) ) { value = false; } else - cvm::fatal_error ("Error: boolean values only are allowed " - "for \""+std::string (key)+"\".\n"); + cvm::fatal_error("Error: boolean values only are allowed " + "for \""+std::string(key)+"\".\n"); if (parse_mode != parse_silent) { - cvm::log ("# "+std::string (key)+" = "+ - (value ? "on" : "off")+"\n"); + cvm::log("# "+std::string(key)+" = "+ + (value ? "on" : "off")+"\n"); } } else { if (b_found_any) { if (parse_mode != parse_silent) { - cvm::log ("# "+std::string (key)+" = on\n"); + cvm::log("# "+std::string(key)+" = on\n"); } value = true; } else { value = def_value; if (parse_mode != parse_silent) { - cvm::log ("# "+std::string (key)+" = "+ - (def_value ? "on" : "off")+" [default]\n"); + cvm::log("# "+std::string(key)+" = "+ + (def_value ? "on" : "off")+" [default]\n"); } } } return b_found_any; } -void colvarparse::add_keyword (char const *key) +void colvarparse::add_keyword(char const *key) { for (std::list::iterator ki = allowed_keywords.begin(); ki != allowed_keywords.end(); ki++) { - if (to_lower_cppstr (std::string (key)) == *ki) + if (to_lower_cppstr(std::string(key)) == *ki) return; } // not found in the list // if (cvm::debug()) - // cvm::log ("Registering a new keyword, \""+std::string (key)+"\".\n"); - allowed_keywords.push_back (to_lower_cppstr (std::string (key))); + // cvm::log("Registering a new keyword, \""+std::string (key)+"\".\n"); + allowed_keywords.push_back(to_lower_cppstr(std::string(key))); } -void colvarparse::strip_values (std::string &conf) +void colvarparse::strip_values(std::string &conf) { size_t offset = 0; data_begin_pos.sort(); data_end_pos.sort(); std::list::iterator data_begin = data_begin_pos.begin(); std::list::iterator data_end = data_end_pos.begin(); for ( ; (data_begin != data_begin_pos.end()) && (data_end != data_end_pos.end()) ; data_begin++, data_end++) { // std::cerr << "data_begin, data_end " // << *data_begin << ", " << *data_end // << "\n"; size_t const nchars = *data_end-*data_begin; // std::cerr << "conf[data_begin:data_end] = \"" // << std::string (conf, *data_begin - offset, nchars) // << "\"\n"; - conf.erase (*data_begin - offset, nchars); + conf.erase(*data_begin - offset, nchars); offset += nchars; // std::cerr << ("Stripped config = \"\n"+conf+"\"\n"); } } -int colvarparse::check_keywords (std::string &conf, char const *key) +int colvarparse::check_keywords(std::string &conf, char const *key) { if (cvm::debug()) - cvm::log ("Configuration string for \""+std::string (key)+ - "\": \"\n"+conf+"\".\n"); + cvm::log("Configuration string for \""+std::string(key)+ + "\": \"\n"+conf+"\".\n"); - strip_values (conf); + strip_values(conf); // after stripping, the config string has either empty lines, or // lines beginning with a keyword std::string line; - std::istringstream is (conf); - while (std::getline (is, line)) { + std::istringstream is(conf); + while (std::getline(is, line)) { if (line.size() == 0) continue; - if (line.find_first_not_of (white_space) == + if (line.find_first_not_of(white_space) == std::string::npos) continue; std::string uk; - std::istringstream line_is (line); + std::istringstream line_is(line); line_is >> uk; // if (cvm::debug()) // cvm::log ("Checking the validity of \""+uk+"\" from line:\n" + line); - uk = to_lower_cppstr (uk); + uk = to_lower_cppstr(uk); bool found_keyword = false; for (std::list::iterator ki = allowed_keywords.begin(); ki != allowed_keywords.end(); ki++) { if (uk == *ki) { found_keyword = true; break; } } if (!found_keyword) { - cvm::log ("Error: keyword \""+uk+"\" is not supported, " - "or not recognized in this context.\n"); + cvm::log("Error: keyword \""+uk+"\" is not supported, " + "or not recognized in this context.\n"); cvm::set_error_bits(INPUT_ERROR); return COLVARS_ERROR; } } allowed_keywords.clear(); data_begin_pos.clear(); data_end_pos.clear(); return COLVARS_OK; } -std::istream & colvarparse::getline_nocomments (std::istream &is, - std::string &line, - char const delim) +std::istream & colvarparse::getline_nocomments(std::istream &is, + std::string &line, + char const delim) { - std::getline (is, line, delim); - size_t const comment = line.find ('#'); + std::getline(is, line, delim); + size_t const comment = line.find('#'); if (comment != std::string::npos) { - line.erase (comment); + line.erase(comment); } return is; } -bool colvarparse::key_lookup (std::string const &conf, - char const *key_in, - std::string &data, - size_t &save_pos) +bool colvarparse::key_lookup(std::string const &conf, + char const *key_in, + std::string &data, + size_t &save_pos) { // add this keyword to the register (in its camelCase version) - add_keyword (key_in); + add_keyword(key_in); // use the lowercase version from now on - std::string const key (to_lower_cppstr (key_in)); + std::string const key(to_lower_cppstr(key_in)); // "conf_lower" is only used to lookup the keyword, but its value // will be read from "conf", in order not to mess up file names - std::string const conf_lower (to_lower_cppstr (conf)); + std::string const conf_lower(to_lower_cppstr(conf)); // by default, there is no value, unless we found one data = ""; // when the function is invoked without save_pos, ensure that we // start from zero colvarparse::dummy_pos = 0; // start from the first occurrence of key - size_t pos = conf_lower.find (key, save_pos); + size_t pos = conf_lower.find(key, save_pos); // iterate over all instances until it finds the isolated keyword while (true) { if (pos == std::string::npos) { // no valid instance of the keyword has been found return false; } bool b_isolated_left = true, b_isolated_right = true; if (pos > 0) { - if ( std::string ("\n"+white_space+ - "}").find (conf[pos-1]) == + if ( std::string("\n"+white_space+ + "}").find(conf[pos-1]) == std::string::npos ) { // none of the valid delimiting characters is on the left of key b_isolated_left = false; } } if (pos < conf.size()-key.size()-1) { - if ( std::string ("\n"+white_space+ - "{").find (conf[pos+key.size()]) == + if ( std::string("\n"+white_space+ + "{").find(conf[pos+key.size()]) == std::string::npos ) { // none of the valid delimiting characters is on the right of key b_isolated_right = false; } } // check that there are matching braces between here and the end of conf - bool const b_not_within_block = brace_check (conf, pos); + bool const b_not_within_block = brace_check(conf, pos); bool const b_isolated = (b_isolated_left && b_isolated_right && b_not_within_block); if (b_isolated) { // found it break; } else { // try the next occurrence of key - pos = conf_lower.find (key, pos+key.size()); + pos = conf_lower.find(key, pos+key.size()); } } // check it is not between quotes // if ( (conf.find_last_of ("\"", // conf.find_last_of (white_space, pos)) != // std::string::npos) && // (conf.find_first_of ("\"", // conf.find_first_of (white_space, pos)) != // std::string::npos) ) // return false; // save the pointer for a future call (when iterating over multiple // valid instances of the same keyword) save_pos = pos + key.size(); // get the remainder of the line - size_t pl = conf.rfind ("\n", pos); + size_t pl = conf.rfind("\n", pos); size_t line_begin = (pl == std::string::npos) ? 0 : pos; size_t nl = conf.find ("\n", pos); size_t line_end = (nl == std::string::npos) ? conf.size() : nl; - std::string line (conf, line_begin, (line_end-line_begin)); + std::string line(conf, line_begin, (line_end-line_begin)); - size_t data_begin = (to_lower_cppstr (line)).find (key) + key.size(); - data_begin = line.find_first_not_of (white_space, data_begin+1); + size_t data_begin = (to_lower_cppstr(line)).find(key) + key.size(); + data_begin = line.find_first_not_of(white_space, data_begin+1); // size_t data_begin_absolute = data_begin + line_begin; // size_t data_end_absolute = data_begin; if (data_begin != std::string::npos) { - size_t data_end = line.find_last_not_of (white_space) + 1; + size_t data_end = line.find_last_not_of(white_space) + 1; data_end = (data_end == std::string::npos) ? line.size() : data_end; // data_end_absolute = data_end + line_begin; - if (line.find ('{', data_begin) != std::string::npos) { + if (line.find('{', data_begin) != std::string::npos) { size_t brace_count = 1; - size_t brace = line.find ('{', data_begin); // start from the first opening brace + size_t brace = line.find('{', data_begin); // start from the first opening brace while (brace_count > 0) { // find the matching closing brace - brace = line.find_first_of ("{}", brace+1); + brace = line.find_first_of("{}", brace+1); while (brace == std::string::npos) { // add a new line if (line_end >= conf.size()) { - cvm::fatal_error ("Parse error: reached the end while " - "looking for closing brace; until now " - "the following was parsed: \"\n"+ - line+"\".\n"); + cvm::fatal_error("Parse error: reached the end while " + "looking for closing brace; until now " + "the following was parsed: \"\n"+ + line+"\".\n"); return false; } size_t const old_end = line.size(); // data_end_absolute += old_end+1; line_begin = line_end; - nl = conf.find ('\n', line_begin+1); + nl = conf.find('\n', line_begin+1); if (nl == std::string::npos) line_end = conf.size(); else line_end = nl; - line.append (conf, line_begin, (line_end-line_begin)); + line.append(conf, line_begin, (line_end-line_begin)); - brace = line.find_first_of ("{}", old_end); + brace = line.find_first_of("{}", old_end); } if (line[brace] == '{') brace_count++; if (line[brace] == '}') brace_count--; } // set data_begin after the opening brace - data_begin = line.find_first_of ('{', data_begin) + 1; - data_begin = line.find_first_not_of (white_space, - data_begin); + data_begin = line.find_first_of('{', data_begin) + 1; + data_begin = line.find_first_not_of(white_space, + data_begin); // set data_end before the closing brace data_end = brace; - data_end = line.find_last_not_of (white_space+"}", - data_end) + 1; + data_end = line.find_last_not_of(white_space+"}", + data_end) + 1; // data_end_absolute = line_end; if (data_end > line.size()) data_end = line.size(); } - data.append (line, data_begin, (data_end-data_begin)); + data.append(line, data_begin, (data_end-data_begin)); if (data.size() && save_delimiters) { - data_begin_pos.push_back (conf.find (data, pos+key.size())); + data_begin_pos.push_back(conf.find(data, pos+key.size())); data_end_pos.push_back (data_begin_pos.back()+data.size()); // std::cerr << "key = " << key << ", data = \"" // << data << "\", data_begin, data_end = " // << data_begin_pos.back() << ", " << data_end_pos.back() // << "\n"; } } save_pos = line_end; return true; } std::istream & operator>> (std::istream &is, colvarparse::read_block const &rb) { size_t start_pos = is.tellg(); std::string read_key, next; if ( !(is >> read_key) || !(read_key == rb.key) || !(is >> next) ) { // the requested keyword has not been found, or it is not possible // to read data after it is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } if (next != "{") { (*rb.data) = next; return is; } size_t brace_count = 1; std::string line; - while (colvarparse::getline_nocomments (is, line)) { + while (colvarparse::getline_nocomments(is, line)) { size_t br = 0, br_old = 0; - while ( (br = line.find_first_of ("{}", br)) != std::string::npos) { + while ( (br = line.find_first_of("{}", br)) != std::string::npos) { if (line[br] == '{') brace_count++; if (line[br] == '}') brace_count--; br_old = br; br++; } - if (brace_count) (*rb.data).append (line + "\n"); + if (brace_count) (*rb.data).append(line + "\n"); else { - (*rb.data).append (line, 0, br_old); + (*rb.data).append(line, 0, br_old); break; } } if (brace_count) { // end-of-file reached // restore initial position is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); } return is; } -bool colvarparse::brace_check (std::string const &conf, - size_t const start_pos) +bool colvarparse::brace_check(std::string const &conf, + size_t const start_pos) { size_t brace_count = 0; size_t brace = start_pos; - while ( (brace = conf.find_first_of ("{}", brace)) != std::string::npos) { + while ( (brace = conf.find_first_of("{}", brace)) != std::string::npos) { if (conf[brace] == '{') brace_count++; if (conf[brace] == '}') brace_count--; brace++; } if (brace_count != 0) return false; else return true; } diff --git a/lib/colvars/colvarparse.h b/lib/colvars/colvarparse.h index 8ea4ca853..af348464e 100644 --- a/lib/colvars/colvarparse.h +++ b/lib/colvars/colvarparse.h @@ -1,198 +1,198 @@ /// -*- c++ -*- #ifndef COLVARPARSE_H #define COLVARPARSE_H #include #include #include "colvarmodule.h" #include "colvarvalue.h" /// \file colvarparse.h Parsing functions for collective variables /// \brief Base class containing parsing functions; all objects which /// need to parse input inherit from this class colvarparse { protected: /// \brief List of legal keywords for this object: this is updated /// by each call to colvarparse::get_keyval() or /// colvarparse::key_lookup() std::list allowed_keywords; /// \brief List of delimiters for the values of each keyword in the /// configuration string; all keywords will be stripped of their /// values before the keyword check is performed std::list data_begin_pos; /// \brief List of delimiters for the values of each keyword in the /// configuration string; all keywords will be stripped of their /// values before the keyword check is performed std::list data_end_pos; /// \brief Whether or not to accumulate data_begin_pos and /// data_end_pos in key_lookup(); it may be useful to disable /// this after the constructor is called, because other files may be /// read (e.g. restart) that would mess up with the registry; in any /// case, nothing serious happens until check_keywords() is invoked /// (which should happen only right after construction) bool save_delimiters; /// \brief Add a new valid keyword to the list - void add_keyword (char const *key); + void add_keyword(char const *key); /// \brief Remove all the values from the config string - void strip_values (std::string &conf); + void strip_values(std::string &conf); public: inline colvarparse() - : save_delimiters (true) + : save_delimiters(true) {} /// How a keyword is parsed in a string enum Parse_Mode { - /// \brief (default) Read the first instance of a keyword (if + /// \brief(default) Read the first instance of a keyword (if /// any), report its value, and print a warning when there is more /// than one parse_normal, /// \brief Like parse_normal, but don't send any message to the log /// (useful e.g. in restart files when such messages are very /// numerous and redundant) parse_silent }; /// \fn get_keyval bool const get_keyval (std::string const &conf, /// char const *key, _type_ &value, _type_ const &def_value, /// Parse_Mode const parse_mode) \brief Helper function to parse /// keywords in the configuration and get their values /// /// In normal circumstances, you should use either version the /// get_keyval function. Both of them look for the C string "key" /// in the C++ string "conf", and assign the corresponding value (if /// available) to the variable "value" (first version), or assign as /// many values as found to the vector "values" (second version). /// /// If "key" is found but no value is associated to it, the default /// value is provided (either one copy or as many copies as the /// current length of the vector "values" specifies). A message /// will print, unless parse_mode is equal to parse_silent. The /// return value of both forms of get_keyval is true if "key" is /// found (with or without value), and false when "key" is absent in /// the string "conf". If there is more than one instance of the /// keyword, a warning will be raised; instead, to loop over /// multiple instances key_lookup() should be invoked directly. /// /// If you introduce a new data type, add two new instances of this /// functions, or insert this type in the \link colvarvalue \endlink /// wrapper class (colvarvalue.h). #define _get_keyval_scalar_proto_(_type_,_def_value_) \ - bool get_keyval (std::string const &conf, \ + bool get_keyval(std::string const &conf, \ char const *key, \ _type_ &value, \ _type_ const &def_value = _def_value_, \ Parse_Mode const parse_mode = parse_normal) - _get_keyval_scalar_proto_ (int, (int)0); - _get_keyval_scalar_proto_ (size_t, (size_t)0); - _get_keyval_scalar_proto_ (std::string, std::string ("")); - _get_keyval_scalar_proto_ (cvm::real, (cvm::real)0.0); - _get_keyval_scalar_proto_ (cvm::rvector, cvm::rvector()); - _get_keyval_scalar_proto_ (cvm::quaternion, cvm::quaternion()); - _get_keyval_scalar_proto_ (colvarvalue, colvarvalue (colvarvalue::type_notset)); - _get_keyval_scalar_proto_ (bool, false); + _get_keyval_scalar_proto_(int, (int)0); + _get_keyval_scalar_proto_(size_t, (size_t)0); + _get_keyval_scalar_proto_(std::string, std::string("")); + _get_keyval_scalar_proto_(cvm::real, (cvm::real)0.0); + _get_keyval_scalar_proto_(cvm::rvector, cvm::rvector()); + _get_keyval_scalar_proto_(cvm::quaternion, cvm::quaternion()); + _get_keyval_scalar_proto_(colvarvalue, colvarvalue(colvarvalue::type_notset)); + _get_keyval_scalar_proto_(bool, false); #define _get_keyval_vector_proto_(_type_,_def_value_) \ - bool get_keyval (std::string const &conf, \ + bool get_keyval(std::string const &conf, \ char const *key, \ std::vector<_type_> &values, \ std::vector<_type_> const &def_values = \ std::vector<_type_> (0, static_cast<_type_>(_def_value_)), \ Parse_Mode const parse_mode = parse_normal) - _get_keyval_vector_proto_ (int, 0); - _get_keyval_vector_proto_ (size_t, 0); - _get_keyval_vector_proto_ (std::string, std::string ("")); - _get_keyval_vector_proto_ (cvm::real, 0.0); - _get_keyval_vector_proto_ (cvm::rvector, cvm::rvector()); - _get_keyval_vector_proto_ (cvm::quaternion, cvm::quaternion()); - _get_keyval_vector_proto_ (colvarvalue, colvarvalue (colvarvalue::type_notset)); + _get_keyval_vector_proto_(int, 0); + _get_keyval_vector_proto_(size_t, 0); + _get_keyval_vector_proto_(std::string, std::string("")); + _get_keyval_vector_proto_(cvm::real, 0.0); + _get_keyval_vector_proto_(cvm::rvector, cvm::rvector()); + _get_keyval_vector_proto_(cvm::quaternion, cvm::quaternion()); + _get_keyval_vector_proto_(colvarvalue, colvarvalue(colvarvalue::type_notset)); /// \brief Check that all the keywords within "conf" are in the list /// of allowed keywords; this will invoke strip_values() first and /// then loop over all words - int check_keywords (std::string &conf, char const *key); + int check_keywords(std::string &conf, char const *key); /// \brief Return a lowercased copy of the string - static inline std::string to_lower_cppstr (std::string const &in) + static inline std::string to_lower_cppstr(std::string const &in) { std::string out = ""; for (size_t i = 0; i < in.size(); i++) { - out.append (1, (char) ::tolower (in[i]) ); + out.append(1, (char) ::tolower(in[i]) ); } return out; } /// \brief Helper class to read a block of the type "key { ... }" /// from a stream and store it in a string /// /// Useful on restarts, where the file is too big to be loaded in a /// string by key_lookup; it can only check that the keyword is /// correct and the block is properly delimited by braces, not /// skipping other blocks class read_block { std::string const key; std::string * const data; public: - inline read_block (std::string const &key_in, std::string &data_in) - : key (key_in), data (&data_in) + inline read_block(std::string const &key_in, std::string &data_in) + : key(key_in), data(&data_in) {} inline ~read_block() {} friend std::istream & operator >> (std::istream &is, read_block const &rb); }; /// Accepted white space delimiters, used in key_lookup() static std::string const white_space; /// \brief Low-level function for parsing configuration strings; /// automatically adds the requested keywords to the list of valid /// ones. \param conf the content of the configuration file or one /// of its blocks \param key the keyword to search in "conf" \param /// data (optional) holds the string provided after "key", if any /// \param save_pos (optional) stores the position of the keyword /// within "conf", useful when doing multiple calls \param /// save_delimiters (optional) - bool key_lookup (std::string const &conf, + bool key_lookup(std::string const &conf, char const *key, std::string &data = dummy_string, size_t &save_pos = dummy_pos); /// Used as a default argument by key_lookup static std::string dummy_string; /// Used as a default argument by key_lookup static size_t dummy_pos; /// \brief Works as std::getline() but also removes everything /// between a comment character and the following newline - static std::istream & getline_nocomments (std::istream &is, + static std::istream & getline_nocomments(std::istream &is, std::string &s, char const delim = '\n'); /// Check if the content of the file has matching braces - bool brace_check (std::string const &conf, + bool brace_check(std::string const &conf, size_t const start_pos = 0); }; #endif diff --git a/lib/colvars/colvarproxy.h b/lib/colvars/colvarproxy.h index ec458d486..e9388f68f 100644 --- a/lib/colvars/colvarproxy.h +++ b/lib/colvars/colvarproxy.h @@ -1,237 +1,230 @@ /// -*- c++ -*- #ifndef COLVARPROXY_H #define COLVARPROXY_H -#ifndef COLVARPROXY_VERSION -#define COLVARPROXY_VERSION "2014-10-21" -#endif - - #include "colvarmodule.h" #include "colvarvalue.h" - // return values for the frame() routine #define COLVARS_NO_SUCH_FRAME -1 -#define COLVARS_NOT_IMPLEMENTED -2 // forward declarations class colvarscript; /// \brief Interface between the collective variables module and /// the simulation or analysis program. /// This is the base class: each program is supported by a derived class. /// Only pure virtual functions ("= 0") must be reimplemented in a new interface. class colvarproxy { public: /// Pointer to the main object colvarmodule *colvars; /// Default constructor - inline colvarproxy() : script (NULL) {} + inline colvarproxy() : script(NULL) {} /// Default destructor virtual inline ~colvarproxy() {} /// (Re)initialize member data after construction virtual void setup() {} // **************** SYSTEM-WIDE PHYSICAL QUANTITIES **************** /// \brief Value of the unit for atomic coordinates with respect to /// angstroms (used by some variables for hard-coded default values) virtual cvm::real unit_angstrom() = 0; /// \brief Boltzmann constant virtual cvm::real boltzmann() = 0; /// \brief Temperature of the simulation (K) virtual cvm::real temperature() = 0; /// \brief Time step of the simulation (fs) virtual cvm::real dt() = 0; /// \brief Pseudo-random number with Gaussian distribution - virtual cvm::real rand_gaussian (void) = 0; + virtual cvm::real rand_gaussian(void) = 0; /// \brief Get the current frame number virtual int frame() { return COLVARS_NOT_IMPLEMENTED; } /// \brief Set the current frame number // return 0 on success, -1 on failure - virtual int frame (int) { return COLVARS_NOT_IMPLEMENTED; } + virtual int frame(int) { return COLVARS_NOT_IMPLEMENTED; } // 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) std::string input_prefix_str, output_prefix_str, restart_output_prefix_str; inline std::string input_prefix() { return input_prefix_str; } /// \brief Prefix to be used for output restart files inline std::string restart_output_prefix() { return restart_output_prefix_str; } /// \brief Prefix to be used for output files (final system /// configuration) inline std::string output_prefix() { return output_prefix_str; } /// \brief Restarts will be written each time this number of steps has passed virtual size_t restart_frequency() = 0; // **************** ACCESS ATOMIC DATA **************** /// Pass restraint energy value for current timestep to MD engine - virtual void add_energy (cvm::real energy) = 0; + virtual void add_energy(cvm::real energy) = 0; /// Tell the proxy whether system forces are needed (may not always be available) - virtual void request_system_force (bool yesno) = 0; + virtual void request_system_force(bool yesno) = 0; // **************** PERIODIC BOUNDARY CONDITIONS **************** /// \brief Get the PBC-aware distance vector between two positions - virtual cvm::rvector position_distance (cvm::atom_pos const &pos1, + virtual cvm::rvector position_distance(cvm::atom_pos const &pos1, cvm::atom_pos const &pos2) = 0; /// \brief Get the PBC-aware square distance between two positions; /// may be implemented independently from position_distance() for optimization purposes - virtual cvm::real position_dist2 (cvm::atom_pos const &pos1, + virtual cvm::real position_dist2(cvm::atom_pos const &pos1, cvm::atom_pos const &pos2); /// \brief Get the closest periodic image to a reference position /// \param pos The position to look for the closest periodic image /// \param ref_pos The reference position - virtual void select_closest_image (cvm::atom_pos &pos, + virtual void select_closest_image(cvm::atom_pos &pos, cvm::atom_pos const &ref_pos) = 0; /// \brief Perform select_closest_image() on a set of atomic positions /// /// After that, distance vectors can then be calculated directly, /// without using position_distance() - void select_closest_images (std::vector &pos, + void select_closest_images(std::vector &pos, cvm::atom_pos const &ref_pos); // **************** SCRIPTING INTERFACE **************** /// Pointer to the scripting interface object /// (does not need to be allocated in a new interface) colvarscript *script; /// is a user force script defined? bool force_script_defined; /// Do we have a scripting interface? bool have_scripts; /// Run a user-defined colvar forces script virtual int run_force_callback() { return COLVARS_NOT_IMPLEMENTED; } virtual int run_colvar_callback(std::string const &name, std::vector const &cvcs, colvarvalue &value) { return COLVARS_NOT_IMPLEMENTED; } virtual int run_colvar_gradient_callback(std::string const &name, std::vector const &cvcs, - std::vector &gradient) + std::vector > &gradient) { return COLVARS_NOT_IMPLEMENTED; } // **************** INPUT/OUTPUT **************** /// Print a message to the main log - virtual void log (std::string const &message) = 0; + virtual void log(std::string const &message) = 0; /// Print a message to the main log and let the rest of the program handle the error - virtual void error (std::string const &message) = 0; + virtual void error(std::string const &message) = 0; /// Print a message to the main log and exit with error code - virtual void fatal_error (std::string const &message) = 0; + virtual void fatal_error(std::string const &message) = 0; /// Print a message to the main log and exit normally - virtual void exit (std::string const &message) = 0; + virtual void exit(std::string const &message) = 0; /// \brief Read atom identifiers from a file \param filename name of /// the file (usually a PDB) \param atoms array to which atoms read /// from "filename" will be appended \param pdb_field (optiona) if /// "filename" is a PDB file, use this field to determine which are /// the atoms to be set - virtual int load_atoms (char const *filename, + virtual int load_atoms(char const *filename, std::vector &atoms, std::string const &pdb_field, double const pdb_field_value = 0.0) = 0; /// \brief Load the coordinates for a group of atoms from a file /// (usually a PDB); if "pos" is already allocated, the number of its /// elements must match the number of atoms in "filename" - virtual int load_coords (char const *filename, + virtual int load_coords(char const *filename, std::vector &pos, const std::vector &indices, std::string const &pdb_field, double const pdb_field_value = 0.0) = 0; /// \brief Rename the given file, before overwriting it - virtual int backup_file (char const *filename) + virtual int backup_file(char const *filename) { return COLVARS_NOT_IMPLEMENTED; } }; -inline void colvarproxy::select_closest_images (std::vector &pos, +inline void colvarproxy::select_closest_images(std::vector &pos, cvm::atom_pos const &ref_pos) { for (std::vector::iterator pi = pos.begin(); pi != pos.end(); ++pi) { - select_closest_image (*pi, ref_pos); + select_closest_image(*pi, ref_pos); } } -inline cvm::real colvarproxy::position_dist2 (cvm::atom_pos const &pos1, +inline cvm::real colvarproxy::position_dist2(cvm::atom_pos const &pos1, cvm::atom_pos const &pos2) { - return (position_distance (pos1, pos2)).norm2(); + return (position_distance(pos1, pos2)).norm2(); } #endif diff --git a/lib/colvars/colvarscript.cpp b/lib/colvars/colvarscript.cpp index 13dffd35d..0c3a90efb 100644 --- a/lib/colvars/colvarscript.cpp +++ b/lib/colvars/colvarscript.cpp @@ -1,301 +1,346 @@ // -*- c++ -*- #include +#include +#include + #include "colvarscript.h" -colvarscript::colvarscript (colvarproxy *p) - : proxy (p), - colvars (p->colvars), - proxy_error (0) +colvarscript::colvarscript(colvarproxy *p) + : proxy(p), + colvars(p->colvars), + proxy_error(0) { } /// Run method based on given arguments -int colvarscript::run (int argc, char const *argv[]) { +int colvarscript::run(int argc, char const *argv[]) { result = ""; if (cvm::debug()) { - cvm::log ("Called script run with " + cvm::to_str(argc) + " args"); - for (int i = 0; i < argc; i++) { cvm::log (argv[i]); } + cvm::log("Called script run with " + cvm::to_str(argc) + " args"); + for (int i = 0; i < argc; i++) { cvm::log(argv[i]); } } if (argc < 2) { - result = "usage: "+std::string (argv[0])+" [args...]\n\ + result = "usage: "+std::string(argv[0])+" [args...]\n\ \n\ Managing the colvars module:\n\ configfile -- read configuration from a file\n\ config -- read configuration from the given string\n\ reset -- delete all internal configuration\n\ delete -- delete this colvars module instance\n\ \n\ Input and output:\n\ list -- return a list of all variables\n\ list biases -- return a list of all biases\n\ load -- load a state file (requires configuration)\n\ update -- recalculate colvars and biases based\n\ printframe -- return a summary of the current frame\n\ printframelabels -- return labels to annotate printframe's output\n"; if (proxy->frame() != COLVARS_NOT_IMPLEMENTED) { result += "\ frame -- return current frame number\n\ frame -- set frame number\n"; } result += "\n\ Accessing collective variables:\n\ colvar value -- return the current value of the colvar \n\ colvar update -- recalculate the colvar \n\ colvar delete -- delete the colvar \n\ colvar addforce -- apply given force on \n\ \n\ Accessing biases:\n\ bias energy -- return the current energy of the bias \n\ bias update -- recalculate the bias \n\ bias delete -- delete the bias \n\ \n\ "; return COLVARSCRIPT_OK; } std::string cmd = argv[1]; if (cmd == "colvar") { - return proc_colvar (argc-1, &(argv[1])); + return proc_colvar(argc-1, &(argv[1])); } if (cmd == "bias") { - return proc_bias (argc-1, &(argv[1])); + return proc_bias(argc-1, &(argv[1])); } if (cmd == "reset") { /// Delete every child object colvars->reset(); return COLVARSCRIPT_OK; } if (cmd == "delete") { colvars->reset(); // Note: the delete bit may be ignored by some backends // it is mostly useful in VMD colvars->set_error_bits(DELETE_COLVARS); return COLVARSCRIPT_OK; } if (cmd == "update") { colvars->calc(); return COLVARSCRIPT_OK; } if (cmd == "list") { if (argc == 2) { for (std::vector::iterator cvi = colvars->colvars.begin(); cvi != colvars->colvars.end(); ++cvi) { result += (cvi == colvars->colvars.begin() ? "" : " ") + (*cvi)->name; } return COLVARSCRIPT_OK; } else if (argc == 3 && !strcmp(argv[2], "biases")) { for (std::vector::iterator bi = colvars->biases.begin(); bi != colvars->biases.end(); ++bi) { result += (bi == colvars->biases.begin() ? "" : " ") + (*bi)->name; } return COLVARSCRIPT_OK; } else { result = "Wrong arguments to command \"list\""; return COLVARSCRIPT_ERROR; } } /// Parse config from file if (cmd == "configfile") { if (argc < 3) { result = "Missing arguments"; return COLVARSCRIPT_ERROR; } - if (colvars->config_file (argv[2]) == COLVARS_OK) { + if (colvars->config_file(argv[2]) == COLVARS_OK) { return COLVARSCRIPT_OK; } else { return COLVARSCRIPT_ERROR; } } /// Parse config from string if (cmd == "config") { if (argc < 3) { result = "Missing arguments"; return COLVARSCRIPT_ERROR; } std::string conf = argv[2]; - if (colvars->config_string (conf) == COLVARS_OK) { + if (colvars->config_string(conf) == COLVARS_OK) { return COLVARSCRIPT_OK; } else { return COLVARSCRIPT_ERROR; } } /// Load an input state file if (cmd == "load") { if (argc < 3) { result = "Missing arguments"; return COLVARSCRIPT_ERROR; } proxy->input_prefix_str = argv[2]; if (colvars->setup_input() == COLVARS_OK) { return COLVARSCRIPT_OK; } else { return COLVARSCRIPT_ERROR; } } /// TODO Write an output state file? (Useful for testing) /// Print the values that would go on colvars.traj if (cmd == "printframelabels") { std::ostringstream os; - colvars->write_traj_label (os); + colvars->write_traj_label(os); result = os.str(); return COLVARSCRIPT_OK; } if (cmd == "printframe") { std::ostringstream os; - colvars->write_traj (os); + colvars->write_traj(os); result = os.str(); return COLVARSCRIPT_OK; } if (cmd == "frame") { if (argc == 2) { int f = proxy->frame(); if (f >= 0) { - result = cvm::to_str (f); + result = cvm::to_str(f); return COLVARSCRIPT_OK; } else { result = "Frame number is not available"; return COLVARSCRIPT_ERROR; } } else if (argc == 3) { // Failure of this function does not trigger an error, but // returns the plain result to let scripts detect available frames long int f = proxy->frame(strtol(argv[2], NULL, 10)); colvars->it = proxy->frame(); - result = cvm::to_str (f); + result = cvm::to_str(f); return COLVARSCRIPT_OK; } else { result = "Wrong arguments to command \"frame\""; return COLVARSCRIPT_ERROR; } } result = "Syntax error"; return COLVARSCRIPT_ERROR; } -int colvarscript::proc_colvar (int argc, char const *argv[]) { +int colvarscript::proc_colvar(int argc, char const *argv[]) { std::string name = argv[1]; - colvar *cv = cvm::colvar_by_name (name); + colvar *cv = cvm::colvar_by_name(name); if (cv == NULL) { result = "Colvar not found: " + name; return COLVARSCRIPT_ERROR; } if (argc < 3) { result = "Missing parameters"; return COLVARSCRIPT_ERROR; } std::string subcmd = argv[2]; if (subcmd == "value") { - result = cvm::to_str(cv->value(), 0, cvm::cv_prec); + result = (cv->value()).to_simple_string(); + return COLVARSCRIPT_OK; + } + + if (subcmd == "width") { + result = cvm::to_str(cv->width, 0, cvm::cv_prec); return COLVARSCRIPT_OK; } if (subcmd == "update") { cv->calc(); cv->update(); - result = cvm::to_str(cv->value(), 0, cvm::cv_prec); + result = (cv->value()).to_simple_string(); return COLVARSCRIPT_OK; } if (subcmd == "delete") { if (cv->biases.size() > 0) { result = "Cannot delete a colvar currently used by biases, delete those biases first"; return COLVARSCRIPT_ERROR; } // colvar destructor is tasked with the cleanup delete cv; // TODO this could be done by the destructors - colvars->write_traj_label (colvars->cv_traj_os); + colvars->write_traj_label(colvars->cv_traj_os); return COLVARSCRIPT_OK; } if (subcmd == "addforce") { if (argc < 4) { - result = "Missing parameter: force value"; + result = "addforce: missing parameter: force value"; return COLVARSCRIPT_ERROR; } std::string f_str = argv[3]; - std::istringstream is (f_str); + std::istringstream is(f_str); is.width(cvm::cv_width); is.precision(cvm::cv_prec); - colvarvalue force (cv->type()); + colvarvalue force(cv->value()); force.is_derivative(); - if (!(is >> force)) { - result = "Error parsing force value"; + if (force.from_simple_string(is.str()) != COLVARS_OK) { + result = "addforce : error parsing force value"; return COLVARSCRIPT_ERROR; } cv->add_bias_force(force); - result = cvm::to_str(force, cvm::cv_width, cvm::cv_prec); + result = force.to_simple_string(); return COLVARSCRIPT_OK; } result = "Syntax error"; return COLVARSCRIPT_ERROR; } -int colvarscript::proc_bias (int argc, char const *argv[]) { +int colvarscript::proc_bias(int argc, char const *argv[]) { std::string name = argv[1]; - colvarbias *b = cvm::bias_by_name (name); + colvarbias *b = cvm::bias_by_name(name); if (b == NULL) { result = "Bias not found: " + name; return COLVARSCRIPT_ERROR; } if (argc < 3) { result = "Missing parameters"; return COLVARSCRIPT_ERROR; } std::string subcmd = argv[2]; if (subcmd == "energy") { result = cvm::to_str(b->get_energy()); return COLVARSCRIPT_OK; } if (subcmd == "update") { b->update(); result = cvm::to_str(b->get_energy()); return COLVARSCRIPT_OK; } + // Subcommands for MW ABF + if (subcmd == "bin") { + int r = b->current_bin(); + result = cvm::to_str(r); + return COLVARSCRIPT_OK; + } + + if (subcmd == "binnum") { + int r = b->bin_num(); + if (r < 0) { + result = "Error: calling bin_num() for bias " + b->name; + return COLVARSCRIPT_ERROR; + } + result = cvm::to_str(r); + return COLVARSCRIPT_OK; + } + + if (subcmd == "share") { + int r = b->replica_share(); + if (r < 0) { + result = "Error: calling replica_share() for bias " + b->name; + return COLVARSCRIPT_ERROR; + } + result = cvm::to_str(r); + return COLVARSCRIPT_OK; + } + // End commands for MW ABF + if (subcmd == "delete") { // the bias destructor takes care of the cleanup at cvm level delete b; // TODO this could be done by the destructors - colvars->write_traj_label (colvars->cv_traj_os); + colvars->write_traj_label(colvars->cv_traj_os); return COLVARSCRIPT_OK; } if (argc >= 4) { -// std::string param = argv[3]; + std::string param = argv[3]; + if (subcmd == "count") { + int index; + if (!(std::istringstream(param) >> index)) { + result = "bin_count: error parsing bin index"; + return COLVARSCRIPT_ERROR; + } + result = cvm::to_str(b->bin_count(index)); + return COLVARSCRIPT_OK; + } result = "Syntax error"; return COLVARSCRIPT_ERROR; } result = "Syntax error"; return COLVARSCRIPT_ERROR; } diff --git a/lib/colvars/colvarscript.h b/lib/colvars/colvarscript.h index 4a9f37a2f..8057802ed 100644 --- a/lib/colvars/colvarscript.h +++ b/lib/colvars/colvarscript.h @@ -1,47 +1,47 @@ /// -*- c++ -*- #ifndef COLVARSCRIPT_H #define COLVARSCRIPT_H #include #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarbias.h" #include "colvarproxy.h" #define COLVARSCRIPT_ERROR -1 #define COLVARSCRIPT_OK 0 class colvarscript { private: colvarproxy *proxy; colvarmodule *colvars; inline colvarscript() {} // no-argument construction forbidden public: friend class colvarproxy; colvarscript(colvarproxy * p); inline ~colvarscript() {} /// If an error is caught by the proxy through fatal_error(), this is set to COLVARSCRIPT_ERROR int proxy_error; /// If an error is returned by one of the methods, it should set this to the error message std::string result; /// Run script command with given positional arguments - int run (int argc, char const *argv[]); + int run(int argc, char const *argv[]); /// Run subcommands on colvar - int proc_colvar (int argc, char const *argv[]); + int proc_colvar(int argc, char const *argv[]); /// Run subcommands on bias - int proc_bias (int argc, char const *argv[]); + int proc_bias(int argc, char const *argv[]); }; #endif diff --git a/lib/colvars/colvartypes.cpp b/lib/colvars/colvartypes.cpp index b24be512a..2ec448bd1 100644 --- a/lib/colvars/colvartypes.cpp +++ b/lib/colvars/colvartypes.cpp @@ -1,615 +1,642 @@ -/// -*- c++ -*- +// -*- c++ -*- + +#include +#include #include "colvarmodule.h" #include "colvartypes.h" #include "colvarparse.h" +std::string cvm::rvector::to_simple_string() const +{ + std::ostringstream os; + os.setf(std::ios::scientific, std::ios::floatfield); + os.precision(cvm::cv_prec); + os << x << " " << y << " " << z; + return os.str(); +} + + +int cvm::rvector::from_simple_string(std::string const &s) +{ + std::stringstream stream(s); + if ( !(stream >> x) || + !(stream >> y) || + !(stream >> z) ) { + return COLVARS_ERROR; + } + return COLVARS_OK; +} + + std::ostream & operator << (std::ostream &os, colvarmodule::rvector const &v) { std::streamsize const w = os.width(); std::streamsize const p = os.precision(); - os.width (2); + os.width(2); os << "( "; - os.width (w); os.precision (p); + os.width(w); os.precision(p); os << v.x << " , "; - os.width (w); os.precision (p); + os.width(w); os.precision(p); os << v.y << " , "; - os.width (w); os.precision (p); + os.width(w); os.precision(p); os << v.z << " )"; return os; } std::istream & operator >> (std::istream &is, colvarmodule::rvector &v) { size_t const start_pos = is.tellg(); char sep; if ( !(is >> sep) || !(sep == '(') || !(is >> v.x) || !(is >> sep) || !(sep == ',') || !(is >> v.y) || !(is >> sep) || !(sep == ',') || !(is >> v.z) || !(is >> sep) || !(sep == ')') ) { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } return is; } +std::string cvm::quaternion::to_simple_string() const +{ + std::ostringstream os; + os.setf(std::ios::scientific, std::ios::floatfield); + os.precision(cvm::cv_prec); + os << q0 << " " << q1 << " " << q2 << " " << q3; + return os.str(); +} +int cvm::quaternion::from_simple_string(std::string const &s) +{ + std::stringstream stream(s); + if ( !(stream >> q0) || + !(stream >> q1) || + !(stream >> q2) || + !(stream >> q3) ) { + return COLVARS_ERROR; + } + return COLVARS_OK; +} std::ostream & operator << (std::ostream &os, colvarmodule::quaternion const &q) { std::streamsize const w = os.width(); std::streamsize const p = os.precision(); - os.width (2); + os.width(2); os << "( "; - os.width (w); os.precision (p); + os.width(w); os.precision(p); os << q.q0 << " , "; - os.width (w); os.precision (p); + os.width(w); os.precision(p); os << q.q1 << " , "; - os.width (w); os.precision (p); + os.width(w); os.precision(p); os << q.q2 << " , "; - os.width (w); os.precision (p); + os.width(w); os.precision(p); os << q.q3 << " )"; return os; } std::istream & operator >> (std::istream &is, colvarmodule::quaternion &q) { size_t const start_pos = is.tellg(); - std::string euler (""); + std::string euler(""); - if ( (is >> euler) && (colvarparse::to_lower_cppstr (euler) == - std::string ("euler")) ) { + if ( (is >> euler) && (colvarparse::to_lower_cppstr(euler) == + std::string("euler")) ) { // parse the Euler angles char sep; cvm::real phi, theta, psi; if ( !(is >> sep) || !(sep == '(') || !(is >> phi) || !(is >> sep) || !(sep == ',') || !(is >> theta) || !(is >> sep) || !(sep == ',') || !(is >> psi) || !(is >> sep) || !(sep == ')') ) { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } - q = colvarmodule::quaternion (phi, theta, psi); + q = colvarmodule::quaternion(phi, theta, psi); } else { // parse the quaternion components - is.seekg (start_pos, std::ios::beg); + is.seekg(start_pos, std::ios::beg); char sep; if ( !(is >> sep) || !(sep == '(') || !(is >> q.q0) || !(is >> sep) || !(sep == ',') || !(is >> q.q1) || !(is >> sep) || !(sep == ',') || !(is >> q.q2) || !(is >> sep) || !(sep == ',') || !(is >> q.q3) || !(is >> sep) || !(sep == ')') ) { is.clear(); - is.seekg (start_pos, std::ios::beg); - is.setstate (std::ios::failbit); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); return is; } } return is; } cvm::quaternion -cvm::quaternion::position_derivative_inner (cvm::rvector const &pos, +cvm::quaternion::position_derivative_inner(cvm::rvector const &pos, cvm::rvector const &vec) const { - cvm::quaternion result (0.0, 0.0, 0.0, 0.0); + cvm::quaternion result(0.0, 0.0, 0.0, 0.0); result.q0 = 2.0 * pos.x * q0 * vec.x +2.0 * pos.y * q0 * vec.y +2.0 * pos.z * q0 * vec.z -2.0 * pos.y * q3 * vec.x +2.0 * pos.z * q2 * vec.x +2.0 * pos.x * q3 * vec.y -2.0 * pos.z * q1 * vec.y -2.0 * pos.x * q2 * vec.z +2.0 * pos.y * q1 * vec.z; result.q1 = +2.0 * pos.x * q1 * vec.x -2.0 * pos.y * q1 * vec.y -2.0 * pos.z * q1 * vec.z +2.0 * pos.y * q2 * vec.x +2.0 * pos.z * q3 * vec.x +2.0 * pos.x * q2 * vec.y -2.0 * pos.z * q0 * vec.y +2.0 * pos.x * q3 * vec.z +2.0 * pos.y * q0 * vec.z; result.q2 = -2.0 * pos.x * q2 * vec.x +2.0 * pos.y * q2 * vec.y -2.0 * pos.z * q2 * vec.z +2.0 * pos.y * q1 * vec.x +2.0 * pos.z * q0 * vec.x +2.0 * pos.x * q1 * vec.y +2.0 * pos.z * q3 * vec.y -2.0 * pos.x * q0 * vec.z +2.0 * pos.y * q3 * vec.z; result.q3 = -2.0 * pos.x * q3 * vec.x -2.0 * pos.y * q3 * vec.y +2.0 * pos.z * q3 * vec.z -2.0 * pos.y * q0 * vec.x +2.0 * pos.z * q1 * vec.x +2.0 * pos.x * q0 * vec.y +2.0 * pos.z * q2 * vec.y +2.0 * pos.x * q1 * vec.z +2.0 * pos.y * q2 * vec.z; return result; } - - // Calculate the optimal rotation between two groups, and implement it // as a quaternion. Uses the method documented in: Coutsias EA, // Seok C, Dill KA. Using quaternions to calculate RMSD. J Comput // Chem. 25(15):1849-57 (2004) DOI: 10.1002/jcc.20110 PubMed: 15376254 -void colvarmodule::rotation::build_matrix (std::vector const &pos1, - std::vector const &pos2, - matrix2d &S) +void colvarmodule::rotation::build_matrix(std::vector const &pos1, + std::vector const &pos2, + cvm::matrix2d &S) { - cvm::rmatrix C; - // build the correlation matrix + C.resize(3, 3); C.reset(); - for (size_t i = 0; i < pos1.size(); i++) { + size_t i; + for (i = 0; i < pos1.size(); i++) { C.xx() += pos1[i].x * pos2[i].x; C.xy() += pos1[i].x * pos2[i].y; C.xz() += pos1[i].x * pos2[i].z; C.yx() += pos1[i].y * pos2[i].x; C.yy() += pos1[i].y * pos2[i].y; C.yz() += pos1[i].y * pos2[i].z; C.zx() += pos1[i].z * pos2[i].x; C.zy() += pos1[i].z * pos2[i].y; C.zz() += pos1[i].z * pos2[i].z; } // build the "overlap" matrix, whose eigenvectors are stationary // points of the RMSD in the space of rotations S[0][0] = C.xx() + C.yy() + C.zz(); S[1][0] = C.yz() - C.zy(); S[0][1] = S[1][0]; S[2][0] = - C.xz() + C.zx() ; S[0][2] = S[2][0]; S[3][0] = C.xy() - C.yx(); S[0][3] = S[3][0]; S[1][1] = C.xx() - C.yy() - C.zz(); S[2][1] = C.xy() + C.yx(); S[1][2] = S[2][1]; S[3][1] = C.xz() + C.zx(); S[1][3] = S[3][1]; S[2][2] = - C.xx() + C.yy() - C.zz(); S[3][2] = C.yz() + C.zy(); S[2][3] = S[3][2]; S[3][3] = - C.xx() - C.yy() + C.zz(); - - // if (cvm::debug()) { - // for (size_t i = 0; i < 4; i++) { - // std::string line (""); - // for (size_t j = 0; j < 4; j++) { - // line += std::string (" S["+cvm::to_str (i)+ - // "]["+cvm::to_str (j)+"] ="+cvm::to_str (S[i][j])); - // } - // cvm::log (line+"\n"); - // } - // } } -void colvarmodule::rotation::diagonalize_matrix (matrix2d &S, - cvm::real S_eigval[4], - matrix2d &S_eigvec) +void colvarmodule::rotation::diagonalize_matrix(cvm::matrix2d &S, + cvm::vector1d &S_eigval, + cvm::matrix2d &S_eigvec) { + S_eigval.resize(4); + S_eigval.reset(); + S_eigvec.resize(4,4); + S_eigvec.reset(); + // diagonalize int jac_nrot = 0; - jacobi (S, S_eigval, S_eigvec, &jac_nrot); - eigsrt (S_eigval, S_eigvec); + jacobi(S.c_array(), S_eigval.c_array(), S_eigvec.c_array(), &jac_nrot); + eigsrt(S_eigval.c_array(), S_eigvec.c_array()); // jacobi saves eigenvectors by columns - transpose (S_eigvec); + transpose(S_eigvec.c_array()); // normalize eigenvectors for (size_t ie = 0; ie < 4; ie++) { cvm::real norm2 = 0.0; size_t i; - for (i = 0; i < 4; i++) norm2 += std::pow (S_eigvec[ie][i], int (2)); - cvm::real const norm = std::sqrt (norm2); - for (i = 0; i < 4; i++) S_eigvec[ie][i] /= norm; + for (i = 0; i < 4; i++) { + norm2 += std::pow(S_eigvec[ie][i], int(2)); + } + cvm::real const norm = std::sqrt(norm2); + for (i = 0; i < 4; i++) { + S_eigvec[ie][i] /= norm; + } } } // Calculate the rotation, plus its derivatives -void colvarmodule::rotation::calc_optimal_rotation -(std::vector const &pos1, - std::vector const &pos2) +void colvarmodule::rotation::calc_optimal_rotation(std::vector const &pos1, + std::vector const &pos2) { - matrix2d S; - matrix2d S_backup; - cvm::real S_eigval[4]; - matrix2d S_eigvec; - -// if (cvm::debug()) { -// cvm::atom_pos cog1 (0.0, 0.0, 0.0); -// for (size_t i = 0; i < pos1.size(); i++) { -// cog1 += pos1[i]; -// } -// cog1 /= cvm::real (pos1.size()); -// cvm::atom_pos cog2 (0.0, 0.0, 0.0); -// for (size_t i = 0; i < pos2.size(); i++) { -// cog2 += pos2[i]; -// } -// cog2 /= cvm::real (pos1.size()); -// cvm::log ("calc_optimal_rotation: centers of geometry are: "+ -// cvm::to_str (cog1, cvm::cv_width, cvm::cv_prec)+ -// " and "+cvm::to_str (cog2, cvm::cv_width, cvm::cv_prec)+".\n"); -// } - - build_matrix (pos1, pos2, S); + S.resize(4,4); + S.reset(); + + build_matrix(pos1, pos2, S); + + S_backup.resize(4,4); S_backup = S; if (cvm::debug()) { if (b_debug_gradients) { - cvm::log ("S = "+cvm::to_str (cvm::to_str (S_backup), cvm::cv_width, cvm::cv_prec)+"\n"); + cvm::log("S = "+cvm::to_str(cvm::to_str(S_backup), cvm::cv_width, cvm::cv_prec)+"\n"); } } - diagonalize_matrix (S, S_eigval, S_eigvec); + diagonalize_matrix(S, S_eigval, S_eigvec); // eigenvalues and eigenvectors - cvm::real const &L0 = S_eigval[0]; - cvm::real const &L1 = S_eigval[1]; - cvm::real const &L2 = S_eigval[2]; - cvm::real const &L3 = S_eigval[3]; - cvm::real const *Q0 = S_eigvec[0]; - cvm::real const *Q1 = S_eigvec[1]; - cvm::real const *Q2 = S_eigvec[2]; - cvm::real const *Q3 = S_eigvec[3]; + cvm::real const L0 = S_eigval[0]; + cvm::real const L1 = S_eigval[1]; + cvm::real const L2 = S_eigval[2]; + cvm::real const L3 = S_eigval[3]; + cvm::quaternion const Q0(S_eigvec[0]); + cvm::quaternion const Q1(S_eigvec[1]); + cvm::quaternion const Q2(S_eigvec[2]); + cvm::quaternion const Q3(S_eigvec[3]); lambda = L0; - q = cvm::quaternion (Q0); + q = Q0; if (q_old.norm2() > 0.0) { - q.match (q_old); - if (q_old.inner (q) < (1.0 - crossing_threshold)) { - cvm::log ("Warning: one molecular orientation has changed by more than "+ - cvm::to_str (crossing_threshold)+": discontinuous rotation ?\n"); + q.match(q_old); + if (q_old.inner(q) < (1.0 - crossing_threshold)) { + cvm::log("Warning: one molecular orientation has changed by more than "+ + cvm::to_str(crossing_threshold)+": discontinuous rotation ?\n"); } } q_old = q; if (cvm::debug()) { if (b_debug_gradients) { - cvm::log ("L0 = "+cvm::to_str (L0, cvm::cv_width, cvm::cv_prec)+ - ", Q0 = "+cvm::to_str (cvm::quaternion (Q0), cvm::cv_width, cvm::cv_prec)+ - ", Q0*Q0 = "+cvm::to_str (cvm::quaternion (Q0).inner (cvm::quaternion (Q0)), cvm::cv_width, cvm::cv_prec)+ - "\n"); - cvm::log ("L1 = "+cvm::to_str (L1, cvm::cv_width, cvm::cv_prec)+ - ", Q1 = "+cvm::to_str (cvm::quaternion (Q1), cvm::cv_width, cvm::cv_prec)+ - ", Q0*Q1 = "+cvm::to_str (cvm::quaternion (Q0).inner (cvm::quaternion (Q1)), cvm::cv_width, cvm::cv_prec)+ - "\n"); - cvm::log ("L2 = "+cvm::to_str (L2, cvm::cv_width, cvm::cv_prec)+ - ", Q2 = "+cvm::to_str (cvm::quaternion (Q2), cvm::cv_width, cvm::cv_prec)+ - ", Q0*Q2 = "+cvm::to_str (cvm::quaternion (Q0).inner (cvm::quaternion (Q2)), cvm::cv_width, cvm::cv_prec)+ - "\n"); - cvm::log ("L3 = "+cvm::to_str (L3, cvm::cv_width, cvm::cv_prec)+ - ", Q3 = "+cvm::to_str (cvm::quaternion (Q3), cvm::cv_width, cvm::cv_prec)+ - ", Q0*Q3 = "+cvm::to_str (cvm::quaternion (Q0).inner (cvm::quaternion (Q3)), cvm::cv_width, cvm::cv_prec)+ - "\n"); + cvm::log("L0 = "+cvm::to_str(L0, cvm::cv_width, cvm::cv_prec)+ + ", Q0 = "+cvm::to_str(Q0, cvm::cv_width, cvm::cv_prec)+ + ", Q0*Q0 = "+cvm::to_str(Q0.inner(Q0), cvm::cv_width, cvm::cv_prec)+ + "\n"); + cvm::log("L1 = "+cvm::to_str(L1, cvm::cv_width, cvm::cv_prec)+ + ", Q1 = "+cvm::to_str(Q1, cvm::cv_width, cvm::cv_prec)+ + ", Q0*Q1 = "+cvm::to_str(Q0.inner(Q1), cvm::cv_width, cvm::cv_prec)+ + "\n"); + cvm::log("L2 = "+cvm::to_str(L2, cvm::cv_width, cvm::cv_prec)+ + ", Q2 = "+cvm::to_str(Q2, cvm::cv_width, cvm::cv_prec)+ + ", Q0*Q2 = "+cvm::to_str(Q0.inner(Q2), cvm::cv_width, cvm::cv_prec)+ + "\n"); + cvm::log("L3 = "+cvm::to_str(L3, cvm::cv_width, cvm::cv_prec)+ + ", Q3 = "+cvm::to_str(Q3, cvm::cv_width, cvm::cv_prec)+ + ", Q0*Q3 = "+cvm::to_str(Q0.inner(Q3), cvm::cv_width, cvm::cv_prec)+ + "\n"); } } // calculate derivatives of L0 and Q0 with respect to each atom in // either group; note: if dS_1 is a null vector, nothing will be // calculated size_t ia; for (ia = 0; ia < dS_1.size(); ia++) { cvm::real const &a2x = pos2[ia].x; cvm::real const &a2y = pos2[ia].y; cvm::real const &a2z = pos2[ia].z; - matrix2d &ds_1 = dS_1[ia]; + cvm::matrix2d &ds_1 = dS_1[ia]; // derivative of the S matrix ds_1.reset(); 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].set(-a2z, 0.0, a2x); ds_1[0][2] = ds_1[2][0]; ds_1[3][0].set( a2y, -a2x, 0.0); ds_1[0][3] = ds_1[3][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].set( a2z, 0.0, a2x); ds_1[1][3] = ds_1[3][1]; 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].set(-a2x, -a2y, a2z); - cvm::rvector &dl0_1 = dL0_1[ia]; - vector1d &dq0_1 = dQ0_1[ia]; + cvm::rvector &dl0_1 = dL0_1[ia]; + cvm::vector1d &dq0_1 = dQ0_1[ia]; // matrix multiplications; derivatives of L_0 and Q_0 are // calculated using Hellmann-Feynman theorem (i.e. exploiting the // fact that the eigenvectors Q_i form an orthonormal basis) dl0_1.reset(); for (size_t i = 0; i < 4; i++) { for (size_t j = 0; j < 4; j++) { dl0_1 += Q0[i] * ds_1[i][j] * Q0[j]; } } dq0_1.reset(); for (size_t p = 0; p < 4; p++) { for (size_t i = 0; i < 4; i++) { for (size_t j = 0; j < 4; j++) { dq0_1[p] += (Q1[i] * ds_1[i][j] * Q0[j]) / (L0-L1) * Q1[p] + (Q2[i] * ds_1[i][j] * Q0[j]) / (L0-L2) * Q2[p] + (Q3[i] * ds_1[i][j] * Q0[j]) / (L0-L3) * Q3[p]; } } } } // do the same for the second group for (ia = 0; ia < dS_2.size(); ia++) { cvm::real const &a1x = pos1[ia].x; cvm::real const &a1y = pos1[ia].y; cvm::real const &a1z = pos1[ia].z; - matrix2d &ds_2 = dS_2[ia]; + cvm::matrix2d &ds_2 = dS_2[ia]; ds_2.reset(); 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].set( a1z, 0.0, -a1x); ds_2[0][2] = ds_2[2][0]; ds_2[3][0].set(-a1y, a1x, 0.0); ds_2[0][3] = ds_2[3][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].set( a1z, 0.0, a1x); ds_2[1][3] = ds_2[3][1]; 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].set(-a1x, -a1y, a1z); - cvm::rvector &dl0_2 = dL0_2[ia]; - vector1d &dq0_2 = dQ0_2[ia]; + cvm::rvector &dl0_2 = dL0_2[ia]; + cvm::vector1d &dq0_2 = dQ0_2[ia]; dl0_2.reset(); for (size_t i = 0; i < 4; i++) { for (size_t j = 0; j < 4; j++) { dl0_2 += Q0[i] * ds_2[i][j] * Q0[j]; } } dq0_2.reset(); for (size_t p = 0; p < 4; p++) { for (size_t i = 0; i < 4; i++) { for (size_t j = 0; j < 4; j++) { dq0_2[p] += (Q1[i] * ds_2[i][j] * Q0[j]) / (L0-L1) * Q1[p] + (Q2[i] * ds_2[i][j] * Q0[j]) / (L0-L2) * Q2[p] + (Q3[i] * ds_2[i][j] * Q0[j]) / (L0-L3) * Q3[p]; } } } if (cvm::debug()) { if (b_debug_gradients) { - matrix2d S_new; - cvm::real S_new_eigval[4]; - matrix2d S_new_eigvec; + cvm::matrix2d S_new(4, 4); + cvm::vector1d S_new_eigval(4); + cvm::matrix2d S_new_eigvec(4, 4); // make an infitesimal move along each cartesian coordinate of // this atom, and solve again the eigenvector problem for (size_t comp = 0; comp < 3; comp++) { S_new = S_backup; // diagonalize the new overlap matrix for (size_t i = 0; i < 4; i++) { for (size_t j = 0; j < 4; j++) { S_new[i][j] += colvarmodule::debug_gradients_step_size * ds_2[i][j][comp]; } } -// cvm::log ("S_new = "+cvm::to_str (cvm::to_str (S_new), cvm::cv_width, cvm::cv_prec)+"\n"); + // cvm::log("S_new = "+cvm::to_str(cvm::to_str (S_new), cvm::cv_width, cvm::cv_prec)+"\n"); - diagonalize_matrix (S_new, S_new_eigval, S_new_eigvec); + diagonalize_matrix(S_new, S_new_eigval, S_new_eigvec); cvm::real const &L0_new = S_new_eigval[0]; - cvm::real const *Q0_new = S_new_eigvec[0]; + cvm::quaternion const Q0_new(S_new_eigvec[0]); cvm::real const DL0 = (dl0_2[comp]) * colvarmodule::debug_gradients_step_size; - cvm::quaternion const q0 (Q0); - cvm::quaternion const DQ0 (dq0_2[0][comp] * colvarmodule::debug_gradients_step_size, - dq0_2[1][comp] * colvarmodule::debug_gradients_step_size, - dq0_2[2][comp] * colvarmodule::debug_gradients_step_size, - dq0_2[3][comp] * colvarmodule::debug_gradients_step_size); - - cvm::log ( "|(l_0+dl_0) - l_0^new|/l_0 = "+ - cvm::to_str (std::fabs (L0+DL0 - L0_new)/L0, cvm::cv_width, cvm::cv_prec)+ - ", |(q_0+dq_0) - q_0^new| = "+ - cvm::to_str ((Q0+DQ0 - Q0_new).norm(), cvm::cv_width, cvm::cv_prec)+ - "\n"); + cvm::quaternion const q0(Q0); + cvm::quaternion const DQ0(dq0_2[0][comp] * colvarmodule::debug_gradients_step_size, + dq0_2[1][comp] * colvarmodule::debug_gradients_step_size, + dq0_2[2][comp] * colvarmodule::debug_gradients_step_size, + dq0_2[3][comp] * colvarmodule::debug_gradients_step_size); + + cvm::log( "|(l_0+dl_0) - l_0^new|/l_0 = "+ + cvm::to_str(std::fabs(L0+DL0 - L0_new)/L0, cvm::cv_width, cvm::cv_prec)+ + ", |(q_0+dq_0) - q_0^new| = "+ + cvm::to_str((Q0+DQ0 - Q0_new).norm(), cvm::cv_width, cvm::cv_prec)+ + "\n"); } } } } } // Numerical Recipes routine for diagonalization #define ROTATE(a,i,j,k,l) g=a[i][j]; \ - h=a[k][l]; \ - a[i][j]=g-s*(h+g*tau); \ + h=a[k][l]; \ + a[i][j]=g-s*(h+g*tau); \ a[k][l]=h+s*(g-h*tau); + #define n 4 -void jacobi(cvm::real **a, cvm::real d[], cvm::real **v, int *nrot) +void jacobi(cvm::real **a, cvm::real *d, cvm::real **v, int *nrot) { int j,iq,ip,i; cvm::real tresh,theta,tau,t,sm,s,h,g,c; - std::vector b (n, 0.0); - std::vector z (n, 0.0); + cvm::vector1d b(n); + cvm::vector1d z(n); for (ip=0;ip 4 && (cvm::real)(std::fabs(d[ip])+g) == (cvm::real)std::fabs(d[ip]) && (cvm::real)(std::fabs(d[iq])+g) == (cvm::real)std::fabs(d[iq])) a[ip][iq]=0.0; else if (std::fabs(a[ip][iq]) > tresh) { h=d[iq]-d[ip]; if ((cvm::real)(std::fabs(h)+g) == (cvm::real)std::fabs(h)) t=(a[ip][iq])/h; else { theta=0.5*h/(a[ip][iq]); t=1.0/(std::fabs(theta)+std::sqrt(1.0+theta*theta)); if (theta < 0.0) t = -t; } c=1.0/std::sqrt(1+t*t); s=t*c; tau=s/(1.0+c); h=t*a[ip][iq]; z[ip] -= h; z[iq] += h; d[ip] -= h; d[iq] += h; a[ip][iq]=0.0; for (j=0;j<=ip-1;j++) { ROTATE(a,j,ip,j,iq) } for (j=ip+1;j<=iq-1;j++) { ROTATE(a,ip,j,j,iq) } for (j=iq+1;j= p) p=d[k=j]; if (k != i) { d[k]=d[i]; d[i]=p; for (j=0;j +#include + +#include "colvarmodule.h" #ifndef PI #define PI 3.14159265358979323846 #endif // ---------------------------------------------------------------------- /// Linear algebra functions and data types used in the collective /// variables implemented so far // ---------------------------------------------------------------------- -/// 1-dimensional vector of real numbers with three components -class colvarmodule::rvector { +/// \brief Arbitrary size array (one dimensions) suitable for linear +/// algebra operations (i.e. for floating point numbers it can be used +/// with library functions) +template class colvarmodule::vector1d +{ +protected: -public: + std::vector data; - cvm::real x, y, z; +public: - inline rvector() - : x (0.0), y (0.0), z (0.0) - {} + /// Default constructor + inline vector1d(size_t const n = 0) + { + data.resize(n); + reset(); + } - inline rvector (cvm::real const &x_i, - cvm::real const &y_i, - cvm::real const &z_i) - : x (x_i), y (y_i), z (z_i) - {} + /// Constructor from C array + inline vector1d(size_t const n, T const *t) + { + data.resize(n); + reset(); + size_t i; + for (i = 0; i < size(); i++) { + data[i] = t[i]; + } + } - inline rvector (cvm::real v) - : x (v), y (v), z (v) - {} + /// Return a pointer to the data location + inline T * c_array() + { + if (data.size() > 0) { + return &(data[0]); + } else { + return NULL; + } + } - /// \brief Set all components to a scalar value - inline void set (cvm::real const &value) { - x = y = z = value; + inline ~vector1d() + { + data.clear(); } - /// \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; + /// Set all elements to zero + inline void reset() + { + data.assign(data.size(), T(0.0)); } - /// \brief Set all components to zero - inline void reset() { - x = y = z = 0.0; + inline size_t size() const + { + return data.size(); } - /// \brief Access cartesian components by index - inline cvm::real & operator [] (int const &i) { - return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x; + inline void resize(size_t const n) + { + data.resize(n); } - /// \brief Access cartesian components by index - inline cvm::real const & operator [] (int const &i) const { - return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x; + inline T & operator [] (size_t const i) { + return data[i]; } + inline T const & operator [] (size_t const i) const { + return data[i]; + } - inline cvm::rvector & operator = (cvm::real const &v) + inline static void check_sizes(vector1d const &v1, vector1d const &v2) { - x = v; - y = v; - z = v; - return *this; + if (v1.size() != v2.size()) { + cvm::error("Error: trying to perform an operation between vectors of different sizes, "+ + cvm::to_str(v1.size())+" and "+cvm::to_str(v2.size())+".\n"); + } } - inline void operator += (cvm::rvector const &v) + inline void operator += (vector1d const &v) { - x += v.x; - y += v.y; - z += v.z; + check_sizes(*this, v); + size_t i; + for (i = 0; i < this->size(); i++) { + (*this)[i] += v[i]; + } } - inline void operator -= (cvm::rvector const &v) + inline void operator -= (vector1d const &v) { - x -= v.x; - y -= v.y; - z -= v.z; + check_sizes(*this, v); + size_t i; + for (i = 0; i < this->size(); i++) { + (*this)[i] -= v[i]; + } } - inline void operator *= (cvm::real const &v) + inline void operator *= (cvm::real const &a) { - x *= v; - y *= v; - z *= v; + size_t i; + for (i = 0; i < this->size(); i++) { + (*this)[i] *= a; + } } - inline void operator /= (cvm::real const& v) + inline void operator /= (cvm::real const &a) { - x /= v; - y /= v; - z /= v; + size_t i; + for (i = 0; i < this->size(); i++) { + (*this)[i] /= a; + } } - inline cvm::real norm2() const + inline friend vector1d operator + (vector1d const &v1, vector1d const &v2) { - return (x*x + y*y + z*z); + check_sizes(v1.size(), v2.size()); + vector1d result(v1.size()); + size_t i; + for (i = 0; i < v1.size(); i++) { + result[i] = v1[i] + v2[i]; + } + return result; } - inline cvm::real norm() const + inline friend vector1d operator - (vector1d const &v1, vector1d const &v2) { - return std::sqrt (this->norm2()); + check_sizes(v1.size(), v2.size()); + vector1d result(v1.size()); + size_t i; + for (i = 0; i < v1.size(); i++) { + result[i] = v1[i] - v2[i]; + } + return result; } - inline cvm::rvector unit() const + inline friend vector1d operator * (vector1d const &v, cvm::real const &a) { - const cvm::real n = this->norm(); - return (n > 0. ? cvm::rvector (x, y, z)/n : cvm::rvector (1., 0., 0.)); + vector1d result(v.size()); + size_t i; + for (i = 0; i < v.size(); i++) { + result[i] = v[i] * a; + } + return result; } - static inline size_t output_width (size_t const &real_width) + inline friend vector1d operator * (cvm::real const &a, vector1d const &v) { - return 3*real_width + 10; + return v * a; } - - static inline cvm::rvector outer (cvm::rvector const &v1, cvm::rvector const &v2) + inline friend vector1d operator / (vector1d const &v, cvm::real const &a) { - return cvm::rvector ( v1.y*v2.z - v2.y*v1.z, - -v1.x*v2.z + v2.x*v1.z, - v1.x*v2.y - v2.x*v1.y); + vector1d result(v.size()); + size_t i; + for (i = 0; i < v.size(); i++) { + result[i] = v[i] / a; + } + return result; } - friend inline cvm::rvector operator - (cvm::rvector const &v) + /// Inner product + inline friend T operator * (vector1d const &v1, vector1d const &v2) { - return cvm::rvector (-v.x, -v.y, -v.z); + check_sizes(v1.size(), v2.size()); + T prod(0.0); + size_t i; + for (i = 0; i < v1.size(); i++) { + prod += v1[i] * v2[i]; + } + return prod; } - friend inline int operator == (cvm::rvector const &v1, cvm::rvector const &v2) + /// Squared norm + inline cvm::real norm2() const { - return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); + cvm::real result = 0.0; + size_t i; + for (i = 0; i < this->size(); i++) { + result += (*this)[i] * (*this)[i]; + } + return result; } - friend inline int operator != (cvm::rvector const &v1, cvm::rvector const &v2) + inline cvm::real norm() const { - return (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z); + return std::sqrt(this->norm2()); } - friend inline cvm::rvector operator + (cvm::rvector const &v1, cvm::rvector const &v2) + /// Slicing + inline vector1d const slice(size_t const i1, size_t const i2) const { - return cvm::rvector (v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); + if ((i2 < i1) || (i2 >= this->size())) { + cvm::error("Error: trying to slice a vector using incorrect boundaries.\n"); + } + vector1d result(i2 - i1); + size_t i; + for (i = 0; i < (i2 - i1); i++) { + result[i] = (*this)[i1+i]; + } + return result; } - friend inline cvm::rvector operator - (cvm::rvector const &v1, cvm::rvector const &v2) + + /// Assign a vector to a slice of this vector + inline void sliceassign(size_t const i1, size_t const i2, vector1d const &v) { - return cvm::rvector (v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + if ((i2 < i1) || (i2 >= this->size())) { + cvm::error("Error: trying to slice a vector using incorrect boundaries.\n"); + } + size_t i; + for (i = 0; i < (i2 - i1); i++) { + (*this)[i1+i] = v[i]; + } } - friend inline cvm::real operator * (cvm::rvector const &v1, cvm::rvector const &v2) + /// Formatted output + + inline size_t output_width(size_t const &real_width) const { - return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; + return real_width*(this->size()) + 3*(this->size()-1) + 4; } - friend inline cvm::rvector operator * (cvm::real const &a, cvm::rvector const &v) + inline friend std::istream & operator >> (std::istream &is, cvm::vector1d &v) { - return cvm::rvector (a*v.x, a*v.y, a*v.z); + if (v.size() == 0) return is; + size_t const start_pos = is.tellg(); + char sep; + if ( !(is >> sep) || !(sep == '(') ) { + is.clear(); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); + return is; + } + size_t count = 0; + while ( (is >> v[count]) && + (count < (v.size()-1) ? ((is >> sep) && (sep == ',')) : true) ) { + if (++count == v.size()) break; + } + if (count < v.size()) { + is.clear(); + is.seekg(start_pos, std::ios::beg); + is.setstate(std::ios::failbit); + } + return is; } - friend inline cvm::rvector operator * (cvm::rvector const &v, cvm::real const &a) + inline friend std::ostream & operator << (std::ostream &os, cvm::vector1d const &v) { - return cvm::rvector (a*v.x, a*v.y, a*v.z); + std::streamsize const w = os.width(); + std::streamsize const p = os.precision(); + + os.width(2); + os << "( "; + size_t i; + for (i = 0; i < v.size()-1; i++) { + os.width(w); os.precision(p); + os << v[i] << " , "; + } + os.width(w); os.precision(p); + os << v[v.size()-1] << " )"; + return os; } - friend inline cvm::rvector operator / (cvm::rvector const &v, cvm::real const &a) + inline std::string to_simple_string() const { - return cvm::rvector (v.x/a, v.y/a, v.z/a); + if (this->size() == 0) return std::string(""); + std::ostringstream os; + os.setf(std::ios::scientific, std::ios::floatfield); + os.precision(cvm::cv_prec); + os << (*this)[0]; + size_t i; + for (i = 1; i < this->size(); i++) { + os << " " << (*this)[i]; + } + return os.str(); } + inline int from_simple_string(std::string const &s) + { + std::stringstream stream(s); + size_t i = 0; + while ((stream >> (*this)[i]) && (i < this->size())) { + i++; + } + if (i < this->size()) { + return COLVARS_ERROR; + } + return COLVARS_OK; + } }; - -/// \brief Arbitrary size array (one dimensions) suitable for linear +/// \brief Arbitrary size array (two dimensions) suitable for linear /// algebra operations (i.e. for floating point numbers it can be used /// with library functions) -template class colvarmodule::vector1d +template class colvarmodule::matrix2d { +public: + + friend class row; + size_t outer_length; + size_t inner_length; + protected: - /// Underlying C-array - T *array; + class row { + public: + T * data; + size_t length; + friend class matrix2d; + inline row(T * const row_data, size_t const inner_length) + : data(row_data), length(inner_length) + {} + inline T & operator [] (size_t const j) { + return *(data+j); + } + inline T const & operator [] (size_t const j) const { + return *(data+j); + } + inline operator vector1d() const + { + return vector1d(length, data); + } + }; + + std::vector data; + std::vector rows; + std::vector pointers; public: - /// Length of the array - inline size_t size() - { - return length; + /// Allocation routine, used by all constructors + inline void resize(size_t const ol, size_t const il) + { + if ((ol > 0) && (il > 0)) { + + if (data.size() > 0) { + // copy previous data + size_t i, j; + std::vector new_data(ol * il); + for (i = 0; i < outer_length; i++) { + for (j = 0; j < inner_length; j++) { + new_data[il*i+j] = data[inner_length*i+j]; + } + } + data.resize(ol * il); + // copy them back + data = new_data; + } else { + data.resize(ol * il); + } + + outer_length = ol; + inner_length = il; + + if (data.size() > 0) { + // rebuild rows + size_t i; + rows.clear(); + rows.reserve(outer_length); + pointers.clear(); + pointers.reserve(outer_length); + for (i = 0; i < outer_length; i++) { + rows.push_back(row(&(data[0])+inner_length*i, inner_length)); + pointers.push_back(&(data[0])+inner_length*i); + } + } + } else { + // zero size + data.clear(); + rows.clear(); + } } - /// Default constructor - inline vector1d (T const &t = T()) - { - array = new T[length]; - reset(); + /// Deallocation routine + inline void clear() { + rows.clear(); + data.clear(); } /// Set all elements to zero inline void reset() { - for (size_t i = 0; i < length; i++) { - array[i] = T (0.0); - } + data.assign(data.size(), T(0.0)); } - /// Constructor from a 1-d C array - inline vector1d (T const *v) + inline size_t size() const { - array = new T[length]; - for (size_t i = 0; i < length; i++) { - array[i] = v[i]; - } + return data.size(); } - /// Copy constructor - inline vector1d (vector1d const &v) + /// Default constructor + inline matrix2d() + : outer_length(0), inner_length(0) { - array = new T[length]; - for (size_t i = 0; i < length; i++) { - array[i] = v.array[i]; - } + this->resize(0, 0); } - /// Assignment - inline vector1d & operator = (vector1d const &v) + inline matrix2d(size_t const ol, size_t const il) + : outer_length(ol), inner_length(il) { - for (size_t i = 0; i < length; i++) { - this->array[i] = v.array[i]; - } - return *this; + this->resize(outer_length, inner_length); + reset(); } - /// Destructor - inline ~vector1d() { - delete [] array; + /// Copy constructor + inline matrix2d(matrix2d const &m) + : outer_length(m.outer_length), inner_length(m.inner_length) + { + // reinitialize data and rows arrays + this->resize(outer_length, inner_length); + // copy data + data = m.data; } - /// Return the 1-d C array - inline T *c_array() { return array; } - - /// Return the 1-d C array - inline operator T *() { return array; } + /// Destructor + inline ~matrix2d() { + this->clear(); + } - /// Inner product - inline friend T operator * (vector1d const &v1, - vector1d const &v2) + inline row & operator [] (size_t const i) { - T prod (0.0); - for (size_t i = 0; i < length; i++) { - prod += v1.array[i] * v2.array[i]; - } - return prod; + return rows[i]; } - - /// Formatted output - friend std::ostream & operator << (std::ostream &os, - vector1d const &v) + inline row const & operator [] (size_t const i) const { - std::streamsize const w = os.width(); - std::streamsize const p = os.precision(); + return rows[i]; + } - os << "( "; - for (size_t i = 0; i < length-1; i++) { - os.width (w); os.precision (p); - os << v.array[i] << " , "; + /// Assignment + inline matrix2d & operator = (matrix2d const &m) + { + if ((outer_length != m.outer_length) || (inner_length != m.inner_length)){ + this->clear(); + outer_length = m.outer_length; + inner_length = m.inner_length; + this->resize(outer_length, inner_length); } - os.width (w); os.precision (p); - os << v.array[length-1] << " )"; - return os; + data = m.data; + return *this; } -}; - - - -/// \brief Arbitrary size array (two dimensions) suitable for linear -/// algebra operations (i.e. for floating point numbers it can be used -/// with library functions) -template class colvarmodule::matrix2d -{ -protected: - - /// Underlying C array - T **array; + /// Return the 2-d C array + inline T ** c_array() { + if (rows.size() > 0) { + return &(pointers[0]); + } else { + return NULL; + } + } -public: + inline static void check_sizes(matrix2d const &m1, matrix2d const &m2) + { + if ((m1.outer_length != m2.outer_length) || + (m1.inner_length != m2.inner_length)) { + cvm::error("Error: trying to perform an operation between matrices of different sizes, "+ + cvm::to_str(m1.outer_length)+"x"+cvm::to_str(m1.inner_length)+" and "+ + cvm::to_str(m2.outer_length)+"x"+cvm::to_str(m2.inner_length)+".\n"); + } + } - /// Allocation routine, used by all constructors - inline void alloc() { - array = new T * [outer_length]; - for (size_t i = 0; i < outer_length; i++) { - array[i] = new T [inner_length]; + inline void operator += (matrix2d const &m) + { + check_sizes(*this, m); + size_t i; + for (i = 0; i < data.size(); i++) { + data[i] += m.data[i]; } } - /// Set all elements to zero - inline void reset() + inline void operator -= (matrix2d const &m) { - for (size_t i = 0; i < outer_length; i++) { - for (size_t j = 0; j < inner_length; j++) { - array[i][j] = T (0.0); - } + check_sizes(*this, m); + size_t i; + for (i = 0; i < data.size(); i++) { + data[i] -= m.data[i]; } } - /// Default constructor - inline matrix2d() + inline void operator *= (cvm::real const &a) { - this->alloc(); - reset(); + size_t i; + for (i = 0; i < data.size(); i++) { + data[i] *= a; + } } - /// Constructor from a 2-d C array - inline matrix2d (T const **m) + inline void operator /= (cvm::real const &a) { - this->alloc(); - for (size_t i = 0; i < outer_length; i++) { - for (size_t j = 0; j < inner_length; j++) - array[i][j] = m[i][j]; + size_t i; + for (i = 0; i < data.size(); i++) { + data[i] /= a; } } - /// Copy constructor - inline matrix2d (matrix2d const &m) + inline friend matrix2d operator + (matrix2d const &m1, matrix2d const &m2) { - this->alloc(); - for (size_t i = 0; i < outer_length; i++) { - for (size_t j = 0; j < inner_length; j++) - this->array[i][j] = m.array[i][j]; + check_sizes(m1, m2); + matrix2d result(m1.outer_length, m1.inner_length); + size_t i; + for (i = 0; i < m1.data.size(); i++) { + result.data[i] = m1.data[i] + m2.data[i]; } + return result; } - /// Assignment - inline matrix2d & - operator = (matrix2d const &m) + inline friend matrix2d operator - (matrix2d const &m1, matrix2d const &m2) { - for (size_t i = 0; i < outer_length; i++) { - for (size_t j = 0; j < inner_length; j++) - this->array[i][j] = m.array[i][j]; + check_sizes(m1, m2); + matrix2d result(m1.outer_length, m1.inner_length); + size_t i; + for (i = 0; i < m1.data.size(); i++) { + result.data[i] = m1.data[i] - m1.data[i]; } - return *this; + return result; } - /// Destructor - inline ~matrix2d() { - for (size_t i = 0; i < outer_length; i++) { - delete [] array[i]; + inline friend matrix2d operator * (matrix2d const &m, cvm::real const &a) + { + matrix2d result(m.outer_length, m.inner_length); + size_t i; + for (i = 0; i < m.data.size(); i++) { + result.data[i] = m.data[i] * a; } - delete [] array; + return result; } - /// Return the 2-d C array - inline T **c_array() { return array; } + inline friend matrix2d operator * (cvm::real const &a, matrix2d const &m) + { + return m * a; + } - /// Return the 2-d C array - inline operator T **() { return array; } - -// /// Matrix addi(c)tion -// inline friend matrix2d -// operator + (matrix2d const &mat1, -// matrix2d const &mat2) { -// matrix2d sum; -// for (size_t i = 0; i < outer_length; i++) { -// for (size_t j = 0; j < inner_length; j++) { -// sum[i][j] = mat1[i][j] + mat2[i][j]; + inline friend matrix2d operator / (matrix2d const &m, cvm::real const &a) + { + matrix2d result(m.outer_length, m.inner_length); + size_t i; + for (i = 0; i < m.data.size(); i++) { + result.data[i] = m.data[i] * a; + } + return result; + } + + /// Matrix multiplication +// inline friend matrix2d const & operator * (matrix2d const &m1, matrix2d const &m2) +// { +// matrix2d result(m1.outer_length, m2.inner_length); +// if (m1.inner_length != m2.outer_length) { +// cvm::error("Error: trying to multiply two matrices of incompatible sizes, "+ +// cvm::to_str(m1.outer_length)+"x"+cvm::to_str(m1.inner_length)+" and "+ +// cvm::to_str(m2.outer_length)+"x"+cvm::to_str(m2.inner_length)+".\n"); +// } else { +// size_t i, j, k; +// for (i = 0; i < m1.outer_length; i++) { +// for (j = 0; j < m2.inner_length; j++) { +// for (k = 0; k < m1.inner_length; k++) { +// result[i][j] += m1[i][k] * m2[k][j]; +// } +// } // } // } +// return result; // } -// /// Matrix subtraction -// inline friend matrix2d -// operator - (matrix2d const &mat1, -// matrix2d const &mat2) { -// matrix2d sum; -// for (size_t i = 0; i < outer_length; i++) { -// for (size_t j = 0; j < inner_length; j++) { -// sum[i][j] = mat1[i][j] - mat2[i][j]; + /// vector-matrix multiplication + inline friend vector1d operator * (vector1d const &v, matrix2d const &m) + { + vector1d result(m.inner_length); + if (m.outer_length != v.size()) { + cvm::error("Error: trying to multiply a vector and a matrix of incompatible sizes, "+ + cvm::to_str(v.size()) + " and " + cvm::to_str(m.outer_length)+"x"+cvm::to_str(m.inner_length) + ".\n"); + } else { + size_t i, k; + for (i = 0; i < m.inner_length; i++) { + for (k = 0; k < m.outer_length; k++) { + result[i] += m[k][i] * v[k]; + } + } + } + return result; + } + +// /// matrix-vector multiplication (unused for now) +// inline friend vector1d const & operator * (matrix2d const &m, vector1d const &v) +// { +// vector1d result(m.outer_length); +// if (m.inner_length != v.size()) { +// cvm::error("Error: trying to multiply a matrix and a vector of incompatible sizes, "+ +// cvm::to_str(m.outer_length)+"x"+cvm::to_str(m.inner_length) +// + " and " + cvm::to_str(v.length) + ".\n"); +// } else { +// size_t i, k; +// for (i = 0; i < m.outer_length; i++) { +// for (k = 0; k < m.inner_length; k++) { +// result[i] += m[i][k] * v[k]; +// } // } // } +// return result; // } /// Formatted output friend std::ostream & operator << (std::ostream &os, - matrix2d const &m) + matrix2d const &m) { std::streamsize const w = os.width(); std::streamsize const p = os.precision(); - os << "("; - for (size_t i = 0; i < outer_length; i++) { + os.width(2); + os << "( "; + size_t i; + for (i = 0; i < m.outer_length; i++) { os << " ( "; - for (size_t j = 0; j < inner_length-1; j++) { - os.width (w); - os.precision (p); - os << m.array[i][j] << " , "; + size_t j; + for (j = 0; j < m.inner_length-1; j++) { + os.width(w); + os.precision(p); + os << m[i][j] << " , "; } - os.width (w); - os.precision (p); - os << m.array[i][inner_length-1] << " )"; + os.width(w); + os.precision(p); + os << m[i][m.inner_length-1] << " )"; } os << " )"; return os; } + inline std::string to_simple_string() const + { + if (this->size() == 0) return std::string(""); + std::ostringstream os; + os.setf(std::ios::scientific, std::ios::floatfield); + os.precision(cvm::cv_prec); + os << (*this)[0]; + size_t i; + for (i = 1; i < data.size(); i++) { + os << " " << data[i]; + } + return os.str(); + } + + inline int from_simple_string(std::string const &s) + { + std::stringstream stream(s); + size_t i = 0; + while ((stream >> data[i]) && (i < data.size())) { + i++; + } + if (i < data.size()) { + return COLVARS_ERROR; + } + return COLVARS_OK; + } + +}; + + +/// vector of real numbers with three components +class colvarmodule::rvector { + +public: + + cvm::real x, y, z; + + inline rvector() + : x(0.0), y(0.0), z(0.0) + {} + + inline rvector(cvm::real const &x_i, + cvm::real const &y_i, + cvm::real const &z_i) + : x(x_i), y(y_i), z(z_i) + {} + + inline rvector(cvm::vector1d const &v) + : x(v[0]), y(v[1]), z(v[2]) + {} + + inline rvector(cvm::real t) + : x(t), y(t), z(t) + {} + + /// \brief Set all components to a scalar value + 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; + } + + /// \brief Access cartesian components by index + inline cvm::real & operator [] (int const &i) { + return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x; + } + + /// \brief Access cartesian components by index + inline cvm::real const & operator [] (int const &i) const { + return (i == 0) ? x : (i == 1) ? y : (i == 2) ? z : x; + } + + inline cvm::vector1d const as_vector() const + { + cvm::vector1d result(3); + result[0] = this->x; + result[1] = this->y; + result[2] = this->z; + return result; + } + + inline cvm::rvector & operator = (cvm::real const &v) + { + x = v; + y = v; + z = v; + return *this; + } + + inline void operator += (cvm::rvector const &v) + { + x += v.x; + y += v.y; + z += v.z; + } + + inline void operator -= (cvm::rvector const &v) + { + x -= v.x; + y -= v.y; + z -= v.z; + } + + inline void operator *= (cvm::real const &v) + { + x *= v; + y *= v; + z *= v; + } + + inline void operator /= (cvm::real const& v) + { + x /= v; + y /= v; + z /= v; + } + + inline cvm::real norm2() const + { + return (x*x + y*y + z*z); + } + + inline cvm::real norm() const + { + return std::sqrt(this->norm2()); + } + + inline cvm::rvector unit() const + { + const cvm::real n = this->norm(); + return (n > 0. ? cvm::rvector(x, y, z)/n : cvm::rvector(1., 0., 0.)); + } + + static inline size_t output_width(size_t const &real_width) + { + return 3*real_width + 10; + } + + + static inline cvm::rvector outer(cvm::rvector const &v1, cvm::rvector const &v2) + { + return cvm::rvector( v1.y*v2.z - v2.y*v1.z, + -v1.x*v2.z + v2.x*v1.z, + v1.x*v2.y - v2.x*v1.y); + } + + friend inline cvm::rvector operator - (cvm::rvector const &v) + { + return cvm::rvector(-v.x, -v.y, -v.z); + } + + friend inline int operator == (cvm::rvector const &v1, cvm::rvector const &v2) + { + return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); + } + + friend inline int operator != (cvm::rvector const &v1, cvm::rvector const &v2) + { + return (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z); + } + + friend inline cvm::rvector operator + (cvm::rvector const &v1, cvm::rvector const &v2) + { + return cvm::rvector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); + } + friend inline cvm::rvector operator - (cvm::rvector const &v1, cvm::rvector const &v2) + { + return cvm::rvector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + friend inline cvm::real operator * (cvm::rvector const &v1, cvm::rvector const &v2) + { + return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; + } + + friend inline cvm::rvector operator * (cvm::real const &a, cvm::rvector const &v) + { + return cvm::rvector(a*v.x, a*v.y, a*v.z); + } + + friend inline cvm::rvector operator * (cvm::rvector const &v, cvm::real const &a) + { + return cvm::rvector(a*v.x, a*v.y, a*v.z); + } + + friend inline cvm::rvector operator / (cvm::rvector const &v, cvm::real const &a) + { + return cvm::rvector(v.x/a, v.y/a, v.z/a); + } + + std::string to_simple_string() const; + int from_simple_string(std::string const &s); }; /// \brief 2-dimensional array of real numbers with three components /// along each dimension (works with colvarmodule::rvector) class colvarmodule::rmatrix - : public colvarmodule::matrix2d { + : public colvarmodule::matrix2d { private: public: /// Return the xx element - inline cvm::real & xx() { return array[0][0]; } + inline cvm::real & xx() { return (*this)[0][0]; } /// Return the xy element - inline cvm::real & xy() { return array[0][1]; } + inline cvm::real & xy() { return (*this)[0][1]; } /// Return the xz element - inline cvm::real & xz() { return array[0][2]; } + inline cvm::real & xz() { return (*this)[0][2]; } /// Return the yx element - inline cvm::real & yx() { return array[1][0]; } + inline cvm::real & yx() { return (*this)[1][0]; } /// Return the yy element - inline cvm::real & yy() { return array[1][1]; } + inline cvm::real & yy() { return (*this)[1][1]; } /// Return the yz element - inline cvm::real & yz() { return array[1][2]; } + inline cvm::real & yz() { return (*this)[1][2]; } /// Return the zx element - inline cvm::real & zx() { return array[2][0]; } + inline cvm::real & zx() { return (*this)[2][0]; } /// Return the zy element - inline cvm::real & zy() { return array[2][1]; } + inline cvm::real & zy() { return (*this)[2][1]; } /// Return the zz element - inline cvm::real & zz() { return array[2][2]; } + inline cvm::real & zz() { return (*this)[2][2]; } /// Return the xx element - inline cvm::real xx() const { return array[0][0]; } + inline cvm::real xx() const { return (*this)[0][0]; } /// Return the xy element - inline cvm::real xy() const { return array[0][1]; } + inline cvm::real xy() const { return (*this)[0][1]; } /// Return the xz element - inline cvm::real xz() const { return array[0][2]; } + inline cvm::real xz() const { return (*this)[0][2]; } /// Return the yx element - inline cvm::real yx() const { return array[1][0]; } + inline cvm::real yx() const { return (*this)[1][0]; } /// Return the yy element - inline cvm::real yy() const { return array[1][1]; } + inline cvm::real yy() const { return (*this)[1][1]; } /// Return the yz element - inline cvm::real yz() const { return array[1][2]; } + inline cvm::real yz() const { return (*this)[1][2]; } /// Return the zx element - inline cvm::real zx() const { return array[2][0]; } + inline cvm::real zx() const { return (*this)[2][0]; } /// Return the zy element - inline cvm::real zy() const { return array[2][1]; } + inline cvm::real zy() const { return (*this)[2][1]; } /// Return the zz element - inline cvm::real zz() const { return array[2][2]; } - - /// Constructor from a 2-d C array - inline rmatrix (cvm::real const **m) - : cvm::matrix2d (m) - {} + inline cvm::real zz() const { return (*this)[2][2]; } /// Default constructor inline rmatrix() - : cvm::matrix2d() + : cvm::matrix2d(3, 3) {} /// Constructor component by component - inline rmatrix (cvm::real const &xxi, - cvm::real const &xyi, - cvm::real const &xzi, - cvm::real const &yxi, - cvm::real const &yyi, - cvm::real const &yzi, - cvm::real const &zxi, - cvm::real const &zyi, - cvm::real const &zzi) - : cvm::matrix2d() + inline rmatrix(cvm::real const &xxi, + cvm::real const &xyi, + cvm::real const &xzi, + cvm::real const &yxi, + cvm::real const &yyi, + cvm::real const &yzi, + cvm::real const &zxi, + cvm::real const &zyi, + cvm::real const &zzi) + : cvm::matrix2d(3, 3) { this->xx() = xxi; this->xy() = xyi; this->xz() = xzi; this->yx() = yxi; this->yy() = yyi; this->yz() = yzi; this->zx() = zxi; this->zy() = zyi; this->zz() = zzi; } /// Destructor inline ~rmatrix() {} /// Return the determinant inline cvm::real determinant() const { return ( xx() * (yy()*zz() - zy()*yz())) - (yx() * (xy()*zz() - zy()*xz())) + (zx() * (xy()*yz() - yy()*xz())); } inline cvm::rmatrix transpose() const { - return cvm::rmatrix (this->xx(), - this->yx(), - this->zx(), - this->xy(), - this->yy(), - this->zy(), - this->xz(), - this->yz(), - this->zz()); + return cvm::rmatrix(this->xx(), + this->yx(), + this->zx(), + this->xy(), + this->yy(), + this->zy(), + this->xz(), + this->yz(), + this->zz()); } friend cvm::rvector operator * (cvm::rmatrix const &m, cvm::rvector const &r); // friend inline cvm::rmatrix const operator * (cvm::rmatrix const &m1, cvm::rmatrix const &m2) { // return cvm::rmatrix (m1.xx()*m2.xx() + m1.xy()*m2.yx() + m1.xz()*m2.yz(), // m1.xx()*m2.xy() + m1.xy()*m2.yy() + m1.xz()*m2.zy(), // m1.xx()*m2.xz() + m1.xy()*m2.yz() + m1.xz()*m2.zz(), // m1.yx()*m2.xx() + m1.yy()*m2.yx() + m1.yz()*m2.yz(), // m1.yx()*m2.xy() + m1.yy()*m2.yy() + m1.yz()*m2.yy(), // m1.yx()*m2.xz() + m1.yy()*m2.yz() + m1.yz()*m2.yz(), // m1.zx()*m2.xx() + m1.zy()*m2.yx() + m1.zz()*m2.yz(), // m1.zx()*m2.xy() + m1.zy()*m2.yy() + m1.zz()*m2.yy(), // m1.zx()*m2.xz() + m1.zy()*m2.yz() + m1.zz()*m2.yz()); // } }; inline cvm::rvector operator * (cvm::rmatrix const &m, cvm::rvector const &r) { - return cvm::rvector (m.xx()*r.x + m.xy()*r.y + m.xz()*r.z, - m.yx()*r.x + m.yy()*r.y + m.yz()*r.z, - m.zx()*r.x + m.zy()*r.y + m.zz()*r.z); + return cvm::rvector(m.xx()*r.x + m.xy()*r.y + m.xz()*r.z, + m.yx()*r.x + m.yy()*r.y + m.yz()*r.z, + m.zx()*r.x + m.zy()*r.y + m.zz()*r.z); } /// Numerical recipes diagonalization -void jacobi (cvm::real **a, cvm::real d[], cvm::real **v, int *nrot); +void jacobi(cvm::real **a, cvm::real *d, cvm::real **v, int *nrot); /// Eigenvector sort -void eigsrt (cvm::real d[], cvm::real **v); +void eigsrt(cvm::real *d, cvm::real **v); /// Transpose the matrix -void transpose (cvm::real **v); +void transpose(cvm::real **v); /// \brief 1-dimensional vector of real numbers with four components and /// a quaternion algebra class colvarmodule::quaternion { public: cvm::real q0, q1, q2, q3; /// Constructor from a 3-d vector - inline quaternion (cvm::real const &x, cvm::real const &y, cvm::real const &z) - : q0 (0.0), q1 (x), q2 (y), q3 (z) + inline quaternion(cvm::real const &x, cvm::real const &y, cvm::real const &z) + : q0(0.0), q1(x), q2(y), q3(z) {} /// Constructor component by component - inline quaternion (cvm::real const qv[4]) - : q0 (qv[0]), q1 (qv[1]), q2 (qv[2]), q3 (qv[3]) + inline quaternion(cvm::real const qv[4]) + : q0(qv[0]), q1(qv[1]), q2(qv[2]), q3(qv[3]) {} /// Constructor component by component - inline quaternion (cvm::real const &q0i, - cvm::real const &q1i, - cvm::real const &q2i, - cvm::real const &q3i) - : q0 (q0i), q1 (q1i), q2 (q2i), q3 (q3i) + inline quaternion(cvm::real const &q0i, + cvm::real const &q1i, + cvm::real const &q2i, + cvm::real const &q3i) + : q0(q0i), q1(q1i), q2(q2i), q3(q3i) + {} + + inline quaternion(cvm::vector1d const &v) + : q0(v[0]), q1(v[1]), q2(v[2]), q3(v[3]) {} /// "Constructor" after Euler angles (in radians) /// /// http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles - inline void set_from_euler_angles (cvm::real const &phi_in, - cvm::real const &theta_in, - cvm::real const &psi_in) + inline void set_from_euler_angles(cvm::real const &phi_in, + cvm::real const &theta_in, + cvm::real const &psi_in) { - q0 = ( (std::cos (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::cos (psi_in/2.0)) + - (std::sin (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::sin (psi_in/2.0)) ); + q0 = ( (std::cos(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::cos(psi_in/2.0)) + + (std::sin(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::sin(psi_in/2.0)) ); - q1 = ( (std::sin (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::cos (psi_in/2.0)) - - (std::cos (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::sin (psi_in/2.0)) ); + q1 = ( (std::sin(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::cos(psi_in/2.0)) - + (std::cos(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::sin(psi_in/2.0)) ); - q2 = ( (std::cos (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::cos (psi_in/2.0)) + - (std::sin (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::sin (psi_in/2.0)) ); + q2 = ( (std::cos(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::cos(psi_in/2.0)) + + (std::sin(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::sin(psi_in/2.0)) ); - q3 = ( (std::cos (phi_in/2.0)) * (std::cos (theta_in/2.0)) * (std::sin (psi_in/2.0)) - - (std::sin (phi_in/2.0)) * (std::sin (theta_in/2.0)) * (std::cos (psi_in/2.0)) ); + q3 = ( (std::cos(phi_in/2.0)) * (std::cos(theta_in/2.0)) * (std::sin(psi_in/2.0)) - + (std::sin(phi_in/2.0)) * (std::sin(theta_in/2.0)) * (std::cos(psi_in/2.0)) ); } /// \brief Default constructor inline quaternion() { reset(); } /// \brief Set all components to a scalar - inline void set (cvm::real const &value = 0.0) + inline void set(cvm::real const &value = 0.0) { q0 = q1 = q2 = q3 = value; } /// \brief Set all components to zero (null quaternion) inline void reset() { q0 = q1 = q2 = q3 = 0.0; } /// \brief Set the q0 component to 1 and the others to 0 (quaternion /// representing no rotation) inline void reset_rotation() { q0 = 1.0; q1 = q2 = q3 = 0.0; } /// Tell the number of characters required to print a quaternion, given that of a real number - static inline size_t output_width (size_t const &real_width) + static inline size_t output_width(size_t const &real_width) { return 4*real_width + 13; } + std::string to_simple_string() const; + int from_simple_string(std::string const &s); + /// \brief Formatted output operator friend std::ostream & operator << (std::ostream &os, cvm::quaternion const &q); /// \brief Formatted input operator friend std::istream & operator >> (std::istream &is, cvm::quaternion &q); /// Access the quaternion as a 4-d array (return a reference) inline cvm::real & operator [] (int const &i) { switch (i) { case 0: return this->q0; case 1: return this->q1; case 2: return this->q2; case 3: return this->q3; default: - cvm::error ("Error: incorrect quaternion component.\n"); + cvm::error("Error: incorrect quaternion component.\n"); return q0; } } /// Access the quaternion as a 4-d array (return a value) inline cvm::real operator [] (int const &i) const { switch (i) { case 0: return this->q0; case 1: return this->q1; case 2: return this->q2; case 3: return this->q3; default: - cvm::error ("Error: trying to access a quaternion " + cvm::error("Error: trying to access a quaternion " "component which is not between 0 and 3.\n"); return 0.0; } } + inline cvm::vector1d const as_vector() const + { + cvm::vector1d result(4); + result[0] = q0; + result[1] = q1; + result[2] = q2; + result[3] = q3; + return result; + } + /// Square norm of the quaternion inline cvm::real norm2() const { return q0*q0 + q1*q1 + q2*q2 + q3*q3; } /// Norm of the quaternion inline cvm::real norm() const { - return std::sqrt (this->norm2()); + return std::sqrt(this->norm2()); } /// Return the conjugate quaternion inline cvm::quaternion conjugate() const { - return cvm::quaternion (q0, -q1, -q2, -q3); + return cvm::quaternion(q0, -q1, -q2, -q3); } inline void operator *= (cvm::real const &a) { q0 *= a; q1 *= a; q2 *= a; q3 *= a; } inline void operator /= (cvm::real const &a) { q0 /= a; q1 /= a; q2 /= a; q3 /= a; } inline void set_positive() { if (q0 > 0.0) return; q0 = -q0; q1 = -q1; q2 = -q2; q3 = -q3; } inline void operator += (cvm::quaternion const &h) { q0+=h.q0; q1+=h.q1; q2+=h.q2; q3+=h.q3; } inline void operator -= (cvm::quaternion const &h) { q0-=h.q0; q1-=h.q1; q2-=h.q2; q3-=h.q3; } /// Promote a 3-vector to a quaternion - static inline cvm::quaternion promote (cvm::rvector const &v) + static inline cvm::quaternion promote(cvm::rvector const &v) { - return cvm::quaternion (0.0, v.x, v.y, v.z); + return cvm::quaternion(0.0, v.x, v.y, v.z); } /// Return the vector component inline cvm::rvector get_vector() const { - return cvm::rvector (q1, q2, q3); + return cvm::rvector(q1, q2, q3); } friend inline cvm::quaternion operator + (cvm::quaternion const &h, cvm::quaternion const &q) { - return cvm::quaternion (h.q0+q.q0, h.q1+q.q1, h.q2+q.q2, h.q3+q.q3); + return cvm::quaternion(h.q0+q.q0, h.q1+q.q1, h.q2+q.q2, h.q3+q.q3); } friend inline cvm::quaternion operator - (cvm::quaternion const &h, cvm::quaternion const &q) { - return cvm::quaternion (h.q0-q.q0, h.q1-q.q1, h.q2-q.q2, h.q3-q.q3); + return cvm::quaternion(h.q0-q.q0, h.q1-q.q1, h.q2-q.q2, h.q3-q.q3); } /// \brief Provides the quaternion product. \b NOTE: for the inner /// product use: \code h.inner (q); \endcode friend inline cvm::quaternion operator * (cvm::quaternion const &h, cvm::quaternion const &q) { - return cvm::quaternion (h.q0*q.q0 - h.q1*q.q1 - h.q2*q.q2 - h.q3*q.q3, - h.q0*q.q1 + h.q1*q.q0 + h.q2*q.q3 - h.q3*q.q2, - h.q0*q.q2 + h.q2*q.q0 + h.q3*q.q1 - h.q1*q.q3, - h.q0*q.q3 + h.q3*q.q0 + h.q1*q.q2 - h.q2*q.q1); + return cvm::quaternion(h.q0*q.q0 - h.q1*q.q1 - h.q2*q.q2 - h.q3*q.q3, + h.q0*q.q1 + h.q1*q.q0 + h.q2*q.q3 - h.q3*q.q2, + h.q0*q.q2 + h.q2*q.q0 + h.q3*q.q1 - h.q1*q.q3, + h.q0*q.q3 + h.q3*q.q0 + h.q1*q.q2 - h.q2*q.q1); } friend inline cvm::quaternion operator * (cvm::real const &c, cvm::quaternion const &q) { - return cvm::quaternion (c*q.q0, c*q.q1, c*q.q2, c*q.q3); + return cvm::quaternion(c*q.q0, c*q.q1, c*q.q2, c*q.q3); } friend inline cvm::quaternion operator * (cvm::quaternion const &q, cvm::real const &c) { - return cvm::quaternion (q.q0*c, q.q1*c, q.q2*c, q.q3*c); + return cvm::quaternion(q.q0*c, q.q1*c, q.q2*c, q.q3*c); } friend inline cvm::quaternion operator / (cvm::quaternion const &q, cvm::real const &c) { - return cvm::quaternion (q.q0/c, q.q1/c, q.q2/c, q.q3/c); + return cvm::quaternion(q.q0/c, q.q1/c, q.q2/c, q.q3/c); } /// \brief Rotate v through this quaternion (put it in the rotated /// reference frame) - inline cvm::rvector rotate (cvm::rvector const &v) const + inline cvm::rvector rotate(cvm::rvector const &v) const { - return ((*this) * promote (v) * ((*this).conjugate())).get_vector(); + return ((*this) * promote(v) * ((*this).conjugate())).get_vector(); } /// \brief Rotate Q2 through this quaternion (put it in the rotated /// reference frame) - inline cvm::quaternion rotate (cvm::quaternion const &Q2) const + inline cvm::quaternion rotate(cvm::quaternion const &Q2) const { - cvm::rvector const vq_rot = this->rotate (Q2.get_vector()); - return cvm::quaternion (Q2.q0, vq_rot.x, vq_rot.y, vq_rot.z); + cvm::rvector const vq_rot = this->rotate(Q2.get_vector()); + return cvm::quaternion(Q2.q0, vq_rot.x, vq_rot.y, vq_rot.z); } /// Return the 3x3 matrix associated to this quaternion inline cvm::rmatrix rotation_matrix() const { cvm::rmatrix R; R.xx() = q0*q0 + q1*q1 - q2*q2 - q3*q3; R.yy() = q0*q0 - q1*q1 + q2*q2 - q3*q3; R.zz() = q0*q0 - q1*q1 - q2*q2 + q3*q3; R.xy() = 2.0 * (q1*q2 - q0*q3); R.xz() = 2.0 * (q0*q2 + q1*q3); R.yx() = 2.0 * (q0*q3 + q1*q2); R.yz() = 2.0 * (q2*q3 - q0*q1); R.zx() = 2.0 * (q1*q3 - q0*q2); R.zy() = 2.0 * (q0*q1 + q2*q3); return R; } /// \brief Multiply the given vector by the derivative of the given /// (rotated) position with respect to the quaternion - cvm::quaternion position_derivative_inner (cvm::rvector const &pos, - cvm::rvector const &vec) const; + cvm::quaternion position_derivative_inner(cvm::rvector const &pos, + cvm::rvector const &vec) const; /// \brief Return the cosine between the orientation frame /// associated to this quaternion and another - inline cvm::real cosine (cvm::quaternion const &q) const + inline cvm::real cosine(cvm::quaternion const &q) const { - cvm::real const iprod = this->inner (q); + cvm::real const iprod = this->inner(q); return 2.0*iprod*iprod - 1.0; } /// \brief Square distance from another quaternion on the /// 4-dimensional unit sphere: returns the square of the angle along /// the shorter of the two geodesics - inline cvm::real dist2 (cvm::quaternion const &Q2) const + inline cvm::real dist2(cvm::quaternion const &Q2) const { cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 + this->q2*Q2.q2 + this->q3*Q2.q3; - cvm::real const omega = std::acos ( (cos_omega > 1.0) ? 1.0 : - ( (cos_omega < -1.0) ? -1.0 : cos_omega) ); + cvm::real const omega = std::acos( (cos_omega > 1.0) ? 1.0 : + ( (cos_omega < -1.0) ? -1.0 : cos_omega) ); // get the minimum distance: x and -x are the same quaternion if (cos_omega > 0.0) return omega * omega; else return (PI-omega) * (PI-omega); } /// Gradient of the square distance: returns a 4-vector equivalent /// to that provided by slerp - inline cvm::quaternion dist2_grad (cvm::quaternion const &Q2) const + inline cvm::quaternion dist2_grad(cvm::quaternion const &Q2) const { cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 + this->q2*Q2.q2 + this->q3*Q2.q3; - cvm::real const omega = std::acos ( (cos_omega > 1.0) ? 1.0 : - ( (cos_omega < -1.0) ? -1.0 : cos_omega) ); - cvm::real const sin_omega = std::sin (omega); + cvm::real const omega = std::acos( (cos_omega > 1.0) ? 1.0 : + ( (cos_omega < -1.0) ? -1.0 : cos_omega) ); + cvm::real const sin_omega = std::sin(omega); - if (std::fabs (sin_omega) < 1.0E-14) { + if (std::fabs(sin_omega) < 1.0E-14) { // return a null 4d vector - return cvm::quaternion (0.0, 0.0, 0.0, 0.0); + return cvm::quaternion(0.0, 0.0, 0.0, 0.0); } cvm::quaternion const - grad1 ((-1.0)*sin_omega*Q2.q0 + cos_omega*(this->q0-cos_omega*Q2.q0)/sin_omega, - (-1.0)*sin_omega*Q2.q1 + cos_omega*(this->q1-cos_omega*Q2.q1)/sin_omega, - (-1.0)*sin_omega*Q2.q2 + cos_omega*(this->q2-cos_omega*Q2.q2)/sin_omega, - (-1.0)*sin_omega*Q2.q3 + cos_omega*(this->q3-cos_omega*Q2.q3)/sin_omega); + grad1((-1.0)*sin_omega*Q2.q0 + cos_omega*(this->q0-cos_omega*Q2.q0)/sin_omega, + (-1.0)*sin_omega*Q2.q1 + cos_omega*(this->q1-cos_omega*Q2.q1)/sin_omega, + (-1.0)*sin_omega*Q2.q2 + cos_omega*(this->q2-cos_omega*Q2.q2)/sin_omega, + (-1.0)*sin_omega*Q2.q3 + cos_omega*(this->q3-cos_omega*Q2.q3)/sin_omega); if (cos_omega > 0.0) { return 2.0*omega*grad1; } else { return -2.0*(PI-omega)*grad1; } } /// \brief Choose the closest between Q2 and -Q2 and save it back. /// Not required for dist2() and dist2_grad() - inline void match (cvm::quaternion &Q2) const + inline void match(cvm::quaternion &Q2) const { cvm::real const cos_omega = this->q0*Q2.q0 + this->q1*Q2.q1 + this->q2*Q2.q2 + this->q3*Q2.q3; if (cos_omega < 0.0) Q2 *= -1.0; } /// \brief Inner product (as a 4-d vector) with Q2; requires match() /// if the largest overlap is looked for - inline cvm::real inner (cvm::quaternion const &Q2) const + inline cvm::real inner(cvm::quaternion const &Q2) const { cvm::real const prod = this->q0*Q2.q0 + this->q1*Q2.q1 + this->q2*Q2.q2 + this->q3*Q2.q3; return prod; } }; /// \brief A rotation between two sets of coordinates (for the moment /// a wrapper for colvarmodule::quaternion) class colvarmodule::rotation { public: /// \brief The rotation itself (implemented as a quaternion) cvm::quaternion q; /// \brief Eigenvalue corresponding to the optimal rotation cvm::real lambda; /// \brief Perform gradient tests bool b_debug_gradients; /// \brief Positions to superimpose: the rotation should brings pos1 /// into pos2 - std::vector< cvm::atom_pos > pos1, pos2; + std::vector pos1, pos2; + + cvm::rmatrix C; + + cvm::matrix2d S; + cvm::vector1d S_eigval; + cvm::matrix2d S_eigvec; + + /// Used for debugging gradients + cvm::matrix2d S_backup; /// Derivatives of S - std::vector< cvm::matrix2d > dS_1, dS_2; + std::vector< cvm::matrix2d > dS_1, dS_2; /// Derivatives of leading eigenvalue - std::vector< cvm::rvector > dL0_1, dL0_2; + std::vector< cvm::rvector > dL0_1, dL0_2; /// Derivatives of leading eigenvector - std::vector< cvm::vector1d > dQ0_1, dQ0_2; + std::vector< cvm::vector1d > dQ0_1, dQ0_2; /// Allocate space for the derivatives of the rotation - inline void request_group1_gradients (size_t const &n) + inline void request_group1_gradients(size_t const &n) { - dS_1.resize (n, cvm::matrix2d()); - dL0_1.resize (n, cvm::rvector (0.0, 0.0, 0.0)); - dQ0_1.resize (n, cvm::vector1d()); + dS_1.resize(n, cvm::matrix2d(4, 4)); + dL0_1.resize(n, cvm::rvector(0.0, 0.0, 0.0)); + dQ0_1.resize(n, cvm::vector1d(4)); } - inline void request_group2_gradients (size_t const &n) + /// Allocate space for the derivatives of the rotation + inline void request_group2_gradients(size_t const &n) { - dS_2.resize (n, cvm::matrix2d()); - dL0_2.resize (n, cvm::rvector (0.0, 0.0, 0.0)); - dQ0_2.resize (n, cvm::vector1d()); + dS_2.resize(n, cvm::matrix2d(4, 4)); + dL0_2.resize(n, cvm::rvector(0.0, 0.0, 0.0)); + dQ0_2.resize(n, cvm::vector1d(4)); } /// \brief Calculate the optimal rotation and store the /// corresponding eigenvalue and eigenvector in the arguments l0 and /// q0; if the gradients have been previously requested, calculate /// them as well /// /// The method to derive the optimal rotation is defined in: /// Coutsias EA, Seok C, Dill KA. /// Using quaternions to calculate RMSD. /// J Comput Chem. 25(15):1849-57 (2004) /// DOI: 10.1002/jcc.20110 PubMed: 15376254 - void calc_optimal_rotation (std::vector const &pos1, - std::vector const &pos2); + void calc_optimal_rotation(std::vector const &pos1, + std::vector const &pos2); /// Default constructor inline rotation() - : b_debug_gradients (false) + : b_debug_gradients(false) {} /// Constructor after a quaternion - inline rotation (cvm::quaternion const &qi) - : q (qi), - b_debug_gradients (false) + inline rotation(cvm::quaternion const &qi) + : q(qi), + b_debug_gradients(false) { } /// Constructor after an axis of rotation and an angle (in radians) - inline rotation (cvm::real const &angle, cvm::rvector const &axis) - : b_debug_gradients (false) + inline rotation(cvm::real const &angle, cvm::rvector const &axis) + : b_debug_gradients(false) { cvm::rvector const axis_n = axis.unit(); - cvm::real const sina = std::sin (angle/2.0); - q = cvm::quaternion (std::cos (angle/2.0), - sina * axis_n.x, sina * axis_n.y, sina * axis_n.z); + cvm::real const sina = std::sin(angle/2.0); + q = cvm::quaternion(std::cos(angle/2.0), + sina * axis_n.x, sina * axis_n.y, sina * axis_n.z); } /// Destructor inline ~rotation() {} /// Return the rotated vector - inline cvm::rvector rotate (cvm::rvector const &v) const + inline cvm::rvector rotate(cvm::rvector const &v) const { - return q.rotate (v); + return q.rotate(v); } /// Return the inverse of this rotation inline cvm::rotation inverse() const { - return cvm::rotation (this->q.conjugate()); + return cvm::rotation(this->q.conjugate()); } /// Return the associated 3x3 matrix inline cvm::rmatrix matrix() const { return q.rotation_matrix(); } /// \brief Return the spin angle (in degrees) with respect to the /// provided axis (which MUST be normalized) - inline cvm::real spin_angle (cvm::rvector const &axis) const + inline cvm::real spin_angle(cvm::rvector const &axis) const { cvm::rvector const q_vec = q.get_vector(); - cvm::real alpha = (180.0/PI) * 2.0 * std::atan2 (axis * q_vec, q.q0); + cvm::real alpha = (180.0/PI) * 2.0 * std::atan2(axis * q_vec, q.q0); while (alpha > 180.0) alpha -= 360; while (alpha < -180.0) alpha += 360; return alpha; } /// \brief Return the derivative of the spin angle with respect to /// the quaternion - inline cvm::quaternion dspin_angle_dq (cvm::rvector const &axis) const + inline cvm::quaternion dspin_angle_dq(cvm::rvector const &axis) const { cvm::rvector const q_vec = q.get_vector(); cvm::real const iprod = axis * q_vec; if (q.q0 != 0.0) { // cvm::real const x = iprod/q.q0; cvm::real const dspindx = (180.0/PI) * 2.0 * (1.0 / (1.0 + (iprod*iprod)/(q.q0*q.q0))); return - cvm::quaternion ( dspindx * (iprod * (-1.0) / (q.q0*q.q0)), - dspindx * ((1.0/q.q0) * axis.x), - dspindx * ((1.0/q.q0) * axis.y), - dspindx * ((1.0/q.q0) * axis.z)); + cvm::quaternion( dspindx * (iprod * (-1.0) / (q.q0*q.q0)), + dspindx * ((1.0/q.q0) * axis.x), + dspindx * ((1.0/q.q0) * axis.y), + dspindx * ((1.0/q.q0) * axis.z)); } else { // (1/(1+x^2)) ~ (1/x)^2 return - cvm::quaternion ((180.0/PI) * 2.0 * ((-1.0)/iprod), 0.0, 0.0, 0.0); + cvm::quaternion((180.0/PI) * 2.0 * ((-1.0)/iprod), 0.0, 0.0, 0.0); // XX TODO: What if iprod == 0? XX } } /// \brief Return the projection of the orientation vector onto a /// predefined axis - inline cvm::real cos_theta (cvm::rvector const &axis) const + inline cvm::real cos_theta(cvm::rvector const &axis) const { cvm::rvector const q_vec = q.get_vector(); cvm::real const alpha = - (180.0/PI) * 2.0 * std::atan2 (axis * q_vec, q.q0); + (180.0/PI) * 2.0 * std::atan2(axis * q_vec, q.q0); - cvm::real const cos_spin_2 = std::cos (alpha * (PI/180.0) * 0.5); + cvm::real const cos_spin_2 = std::cos(alpha * (PI/180.0) * 0.5); cvm::real const cos_theta_2 = ( (cos_spin_2 != 0.0) ? (q.q0 / cos_spin_2) : (0.0) ); // cos(2t) = 2*cos(t)^2 - 1 return 2.0 * (cos_theta_2*cos_theta_2) - 1.0; } - /// Return the derivative of the tilt wrt the quaternion - inline cvm::quaternion dcos_theta_dq (cvm::rvector const &axis) const + /// Return the derivative of the tilt wrt the quaternion + inline cvm::quaternion dcos_theta_dq(cvm::rvector const &axis) const { cvm::rvector const q_vec = q.get_vector(); cvm::real const iprod = axis * q_vec; - cvm::real const cos_spin_2 = std::cos (std::atan2 (iprod, q.q0)); + cvm::real const cos_spin_2 = std::cos(std::atan2(iprod, q.q0)); if (q.q0 != 0.0) { cvm::real const d_cos_theta_dq0 = (4.0 * q.q0 / (cos_spin_2*cos_spin_2)) * (1.0 - (iprod*iprod)/(q.q0*q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0))); cvm::real const d_cos_theta_dqn = (4.0 * q.q0 / (cos_spin_2*cos_spin_2) * (iprod/q.q0) / (1.0 + (iprod*iprod)/(q.q0*q.q0))); - return cvm::quaternion (d_cos_theta_dq0, - d_cos_theta_dqn * axis.x, - d_cos_theta_dqn * axis.y, - d_cos_theta_dqn * axis.z); + return cvm::quaternion(d_cos_theta_dq0, + d_cos_theta_dqn * axis.x, + d_cos_theta_dqn * axis.y, + d_cos_theta_dqn * axis.z); } else { cvm::real const d_cos_theta_dqn = (4.0 / (cos_spin_2*cos_spin_2 * iprod)); - return cvm::quaternion (0.0, - d_cos_theta_dqn * axis.x, - d_cos_theta_dqn * axis.y, - d_cos_theta_dqn * axis.z); + return cvm::quaternion(0.0, + d_cos_theta_dqn * axis.x, + d_cos_theta_dqn * axis.y, + d_cos_theta_dqn * axis.z); } } /// \brief Threshold for the eigenvalue crossing test static cvm::real crossing_threshold; protected: /// \brief Previous value of the rotation (used to warn the user /// when the structure changes too much, and there may be an /// eigenvalue crossing) cvm::quaternion q_old; /// Build the overlap matrix S (used by calc_optimal_rotation()) - void build_matrix (std::vector const &pos1, - std::vector const &pos2, - cvm::matrix2d &S); + void build_matrix(std::vector const &pos1, + std::vector const &pos2, + cvm::matrix2d &S); /// Diagonalize the overlap matrix S (used by calc_optimal_rotation()) - void diagonalize_matrix (cvm::matrix2d &S, - cvm::real S_eigval[4], - cvm::matrix2d &S_eigvec); + void diagonalize_matrix(cvm::matrix2d &S, + cvm::vector1d &S_eigval, + cvm::matrix2d &S_eigvec); }; #endif diff --git a/lib/colvars/colvarvalue.cpp b/lib/colvars/colvarvalue.cpp index fa209ee19..17f81ec73 100644 --- a/lib/colvars/colvarvalue.cpp +++ b/lib/colvars/colvarvalue.cpp @@ -1,301 +1,640 @@ /// -*- c++ -*- #include +#include +#include #include "colvarmodule.h" #include "colvarvalue.h" -std::string const colvarvalue::type_desc[colvarvalue::type_all+1] = - { "not_set", - "scalar number", - "3-dimensional vector", - "3-dimensional unit vector", - "3-dimensional tangent vector", - "4-dimensional unit quaternion", - "4-dimensional tangent vector", +void colvarvalue::add_elem(colvarvalue const &x) +{ + if (this->value_type != type_vector) { + cvm::error("Error: trying to set an element for a variable that is not set to be a vector.\n"); + return; + } + size_t const n = vector1d_value.size(); + size_t const nd = num_dimensions(x.value_type); + elem_types.push_back(x.value_type); + elem_indices.push_back(n); + elem_sizes.push_back(nd); + vector1d_value.resize(n + nd); + set_elem(n, x); +} + + +colvarvalue const colvarvalue::get_elem(int const i_begin, int const i_end, Type const vt) const +{ + if (vector1d_value.size() > 0) { + cvm::vector1d const v(vector1d_value.slice(i_begin, i_end)); + return colvarvalue(v, vt); + } else { + cvm::error("Error: trying to get an element from a variable that is not a vector.\n"); + return colvarvalue(type_notset); + } +} + + +void colvarvalue::set_elem(int const i_begin, int const i_end, colvarvalue const &x) +{ + if (vector1d_value.size() > 0) { + vector1d_value.sliceassign(i_begin, i_end, x.as_vector()); + } else { + cvm::error("Error: trying to set an element for a variable that is not a vector.\n"); + } +} + + +colvarvalue const colvarvalue::get_elem(int const icv) const +{ + if (elem_types.size() > 0) { + return get_elem(elem_indices[icv], elem_indices[icv] + elem_sizes[icv], + elem_types[icv]); + } else { + cvm::error("Error: trying to get a colvarvalue element from a vector colvarvalue that was initialized as a plain array.\n"); + return colvarvalue(type_notset); + } +} + + +void colvarvalue::set_elem(int const icv, colvarvalue const &x) +{ + if (elem_types.size() > 0) { + check_types_assign(elem_types[icv], x.value_type); + set_elem(elem_indices[icv], elem_indices[icv] + elem_sizes[icv], x); + } else { + cvm::error("Error: trying to set a colvarvalue element for a colvarvalue that was initialized as a plain array.\n"); + } +} + + +colvarvalue colvarvalue::inverse() const +{ + switch (value_type) { + case colvarvalue::type_scalar: + return colvarvalue(1.0/real_value); + break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return colvarvalue(cvm::rvector(1.0/rvector_value.x, + 1.0/rvector_value.y, + 1.0/rvector_value.z)); + break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return colvarvalue(cvm::quaternion(1.0/quaternion_value.q0, + 1.0/quaternion_value.q1, + 1.0/quaternion_value.q2, + 1.0/quaternion_value.q3)); + break; + case colvarvalue::type_vector: + { + cvm::vector1d result(vector1d_value); + if (elem_types.size() > 0) { + // if we have information about non-scalar types, use it + size_t i; + for (i = 0; i < elem_types.size(); i++) { + result.sliceassign(elem_indices[i], elem_indices[i]+elem_sizes[i], + cvm::vector1d((this->get_elem(i)).inverse())); + } + } else { + size_t i; + for (i = 0; i < result.size(); i++) { + if (result[i] != 0.0) { + result = 1.0/result[i]; + } + } + } + return colvarvalue(result, type_vector); + } + break; + case colvarvalue::type_notset: + default: + undef_op(); + break; + } + return colvarvalue(); +} + + +// binary operations between two colvarvalues + +colvarvalue operator + (colvarvalue const &x1, + colvarvalue const &x2) +{ + colvarvalue::check_types(x1, x2); + + switch (x1.value_type) { + case colvarvalue::type_scalar: + return colvarvalue(x1.real_value + x2.real_value); + case colvarvalue::type_3vector: + return colvarvalue(x1.rvector_value + x2.rvector_value); + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return colvarvalue(x1.rvector_value + x2.rvector_value, + colvarvalue::type_unit3vector); + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return colvarvalue(x1.quaternion_value + x2.quaternion_value); + case colvarvalue::type_vector: + return colvarvalue(x1.vector1d_value + x2.vector1d_value, colvarvalue::type_vector); + case colvarvalue::type_notset: + default: + x1.undef_op(); + return colvarvalue(colvarvalue::type_notset); }; +} + + +colvarvalue operator - (colvarvalue const &x1, + colvarvalue const &x2) +{ + colvarvalue::check_types(x1, x2); -std::string const colvarvalue::type_keyword[colvarvalue::type_all+1] = - { "not_set", - "scalar", - "vector", - "unit_vector", - "", - "unit_quaternion", - "", + switch (x1.value_type) { + case colvarvalue::type_scalar: + return colvarvalue(x1.real_value - x2.real_value); + case colvarvalue::type_3vector: + return colvarvalue(x1.rvector_value - x2.rvector_value); + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return colvarvalue(x1.rvector_value - x2.rvector_value, + colvarvalue::type_unit3vector); + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return colvarvalue(x1.quaternion_value - x2.quaternion_value); + case colvarvalue::type_vector: + return colvarvalue(x1.vector1d_value - x2.vector1d_value, colvarvalue::type_vector); + case colvarvalue::type_notset: + default: + x1.undef_op(); + return colvarvalue(colvarvalue::type_notset); }; +} + + +// binary operations with real numbers + +colvarvalue operator * (cvm::real const &a, + colvarvalue const &x) +{ + switch (x.value_type) { + case colvarvalue::type_scalar: + return colvarvalue(a * x.real_value); + case colvarvalue::type_3vector: + return colvarvalue(a * x.rvector_value); + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return colvarvalue(a * x.rvector_value, + colvarvalue::type_unit3vector); + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return colvarvalue(a * x.quaternion_value); + case colvarvalue::type_vector: + return colvarvalue(x.vector1d_value * a, colvarvalue::type_vector); + case colvarvalue::type_notset: + default: + x.undef_op(); + return colvarvalue(colvarvalue::type_notset); + } +} + -size_t const colvarvalue::dof_num[ colvarvalue::type_all+1] = - { 0, 1, 3, 2, 2, 3, 3 }; +colvarvalue operator * (colvarvalue const &x, + cvm::real const &a) +{ + return a * x; +} -void colvarvalue::undef_op() const +colvarvalue operator / (colvarvalue const &x, + cvm::real const &a) { - cvm::error ("Error: Undefined operation on a colvar of type \""+ - colvarvalue::type_desc[this->value_type]+"\".\n"); + switch (x.value_type) { + case colvarvalue::type_scalar: + return colvarvalue(x.real_value / a); + case colvarvalue::type_3vector: + return colvarvalue(x.rvector_value / a); + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return colvarvalue(x.rvector_value / a, + colvarvalue::type_unit3vector); + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return colvarvalue(x.quaternion_value / a); + case colvarvalue::type_vector: + return colvarvalue(x.vector1d_value / a, colvarvalue::type_vector); + case colvarvalue::type_notset: + default: + x.undef_op(); + return colvarvalue(colvarvalue::type_notset); + } +} + + +// inner product between two colvarvalues + +cvm::real operator * (colvarvalue const &x1, + colvarvalue const &x2) +{ + colvarvalue::check_types(x1, x2); + + switch (x1.value_type) { + case colvarvalue::type_scalar: + return (x1.real_value * x2.real_value); + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return (x1.rvector_value * x2.rvector_value); + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + // the "*" product is the quaternion product, here the inner + // member function is used instead + return (x1.quaternion_value.inner(x2.quaternion_value)); + case colvarvalue::type_vector: + return (x1.vector1d_value * x2.vector1d_value); + case colvarvalue::type_notset: + default: + x1.undef_op(); + return 0.0; + }; +} + + +colvarvalue colvarvalue::dist2_grad(colvarvalue const &x2) const +{ + colvarvalue::check_types(*this, x2); + + switch (this->value_type) { + case colvarvalue::type_scalar: + return 2.0 * (this->real_value - x2.real_value); + case colvarvalue::type_3vector: + return 2.0 * (this->rvector_value - x2.rvector_value); + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + { + cvm::rvector const &v1 = this->rvector_value; + cvm::rvector const &v2 = x2.rvector_value; + cvm::real const cos_t = v1 * v2; + cvm::real const sin_t = std::sqrt(1.0 - cos_t*cos_t); + return colvarvalue( 2.0 * sin_t * + cvm::rvector((-1.0) * sin_t * v2.x + + cos_t/sin_t * (v1.x - cos_t*v2.x), + (-1.0) * sin_t * v2.y + + cos_t/sin_t * (v1.y - cos_t*v2.y), + (-1.0) * sin_t * v2.z + + cos_t/sin_t * (v1.z - cos_t*v2.z) + ), + colvarvalue::type_unit3vector ); + } + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return this->quaternion_value.dist2_grad(x2.quaternion_value); + case colvarvalue::type_vector: + return colvarvalue(2.0 * (this->vector1d_value - x2.vector1d_value), colvarvalue::type_vector); + break; + case colvarvalue::type_notset: + default: + this->undef_op(); + return colvarvalue(colvarvalue::type_notset); + }; +} + + +std::string colvarvalue::to_simple_string() const +{ + switch (type()) { + case colvarvalue::type_scalar: + return cvm::to_str(real_value, 0, cvm::cv_prec); + break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return rvector_value.to_simple_string(); + break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return quaternion_value.to_simple_string(); + break; + case colvarvalue::type_vector: + return vector1d_value.to_simple_string(); + break; + case colvarvalue::type_notset: + default: + undef_op(); + break; + } + return std::string(); +} + + +int colvarvalue::from_simple_string(std::string const &s) +{ + switch (type()) { + case colvarvalue::type_scalar: + return ((std::istringstream(s) >> real_value) + ? COLVARS_OK : COLVARS_ERROR); + break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return rvector_value.from_simple_string(s); + break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return quaternion_value.from_simple_string(s); + break; + case colvarvalue::type_vector: + return vector1d_value.from_simple_string(s); + break; + case colvarvalue::type_notset: + default: + undef_op(); + break; + } + return COLVARS_ERROR; +} + +std::ostream & operator << (std::ostream &os, colvarvalue const &x) +{ + switch (x.type()) { + case colvarvalue::type_scalar: + os << x.real_value; + break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + os << x.rvector_value; + break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + os << x.quaternion_value; + break; + case colvarvalue::type_vector: + os << x.vector1d_value; + break; + case colvarvalue::type_notset: + default: + os << "not set"; + break; + } + return os; } -void colvarvalue::error_rside -(colvarvalue::Type const &vt) const + +std::ostream & operator << (std::ostream &os, std::vector const &v) { - cvm::error("Trying to assign a colvar value with type \""+ - type_desc[this->value_type]+"\" to one with type \""+ - type_desc[vt]+"\".\n"); + size_t i; + for (i = 0; i < v.size(); i++) { + os << v[i]; + } + return os; } -void colvarvalue::error_lside(colvarvalue::Type const &vt) const + +std::istream & operator >> (std::istream &is, colvarvalue &x) { - cvm::error("Trying to use a colvar value with type \""+ - type_desc[vt]+"\" as one of type \""+ - type_desc[this->value_type]+"\".\n"); + if (x.type() == colvarvalue::type_notset) { + cvm::error("Trying to read from a stream a colvarvalue, " + "which has not yet been assigned a data type.\n"); + return is; + } + + switch (x.type()) { + case colvarvalue::type_scalar: + is >> x.real_value; + break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vectorderiv: + is >> x.rvector_value; + break; + case colvarvalue::type_unit3vector: + is >> x.rvector_value; + x.apply_constraints(); + break; + case colvarvalue::type_quaternion: + is >> x.quaternion_value; + x.apply_constraints(); + break; + case colvarvalue::type_quaternionderiv: + is >> x.quaternion_value; + break; + case colvarvalue::type_vector: + is >> x.vector1d_value; + break; + case colvarvalue::type_notset: + default: + x.undef_op(); + } + return is; } +size_t colvarvalue::output_width(size_t const &real_width) const +{ + switch (this->value_type) { + case colvarvalue::type_scalar: + return real_width; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return cvm::rvector::output_width(real_width); + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return cvm::quaternion::output_width(real_width); + case colvarvalue::type_vector: + // note how this depends on the vector's size + return vector1d_value.output_width(real_width); + case colvarvalue::type_notset: + default: + return 0; + } +} + void colvarvalue::inner_opt(colvarvalue const &x, std::vector::iterator &xv, std::vector::iterator const &xv_end, - std::vector::iterator &inner) + std::vector::iterator &result) { // doing type check only once, here colvarvalue::check_types(x, *xv); std::vector::iterator &xvi = xv; - std::vector::iterator &ii = inner; + std::vector::iterator &ii = result; switch (x.value_type) { case colvarvalue::type_scalar: while (xvi != xv_end) { *(ii++) += (xvi++)->real_value * x.real_value; } break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: while (xvi != xv_end) { *(ii++) += (xvi++)->rvector_value * x.rvector_value; } break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: while (xvi != xv_end) { - *(ii++) += ((xvi++)->quaternion_value).cosine (x.quaternion_value); + *(ii++) += ((xvi++)->quaternion_value).cosine(x.quaternion_value); + } + break; + case colvarvalue::type_vector: + while (xvi != xv_end) { + *(ii++) += (xvi++)->vector1d_value * x.vector1d_value; } break; default: x.undef_op(); }; } + void colvarvalue::inner_opt(colvarvalue const &x, std::list::iterator &xv, std::list::iterator const &xv_end, - std::vector::iterator &inner) + std::vector::iterator &result) { // doing type check only once, here colvarvalue::check_types(x, *xv); std::list::iterator &xvi = xv; - std::vector::iterator &ii = inner; + std::vector::iterator &ii = result; switch (x.value_type) { case colvarvalue::type_scalar: while (xvi != xv_end) { *(ii++) += (xvi++)->real_value * x.real_value; } break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: while (xvi != xv_end) { *(ii++) += (xvi++)->rvector_value * x.rvector_value; } break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: while (xvi != xv_end) { - *(ii++) += ((xvi++)->quaternion_value).cosine (x.quaternion_value); + *(ii++) += ((xvi++)->quaternion_value).cosine(x.quaternion_value); + } + break; + case colvarvalue::type_vector: + while (xvi != xv_end) { + *(ii++) += (xvi++)->vector1d_value * x.vector1d_value; } break; default: x.undef_op(); }; } void colvarvalue::p2leg_opt(colvarvalue const &x, std::vector::iterator &xv, std::vector::iterator const &xv_end, - std::vector::iterator &inner) + std::vector::iterator &result) { // doing type check only once, here colvarvalue::check_types(x, *xv); std::vector::iterator &xvi = xv; - std::vector::iterator &ii = inner; + std::vector::iterator &ii = result; switch (x.value_type) { case colvarvalue::type_scalar: cvm::error("Error: cannot calculate Legendre polynomials " "for scalar variables.\n"); return; break; - case colvarvalue::type_vector: + case colvarvalue::type_3vector: while (xvi != xv_end) { cvm::real const cosine = ((xvi)->rvector_value * x.rvector_value) / ((xvi)->rvector_value.norm() * x.rvector_value.norm()); xvi++; *(ii++) += 1.5*cosine*cosine - 0.5; } break; - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: while (xvi != xv_end) { cvm::real const cosine = (xvi++)->rvector_value * x.rvector_value; *(ii++) += 1.5*cosine*cosine - 0.5; } break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: while (xvi != xv_end) { - cvm::real const cosine = (xvi++)->quaternion_value.cosine (x.quaternion_value); + cvm::real const cosine = (xvi++)->quaternion_value.cosine(x.quaternion_value); + *(ii++) += 1.5*cosine*cosine - 0.5; + } + break; + case colvarvalue::type_vector: + while (xvi != xv_end) { + cvm::real const cosine = + ((xvi)->vector1d_value * x.vector1d_value) / + ((xvi)->vector1d_value.norm() * x.rvector_value.norm()); + xvi++; *(ii++) += 1.5*cosine*cosine - 0.5; } break; default: x.undef_op(); }; } + void colvarvalue::p2leg_opt(colvarvalue const &x, std::list::iterator &xv, std::list::iterator const &xv_end, - std::vector::iterator &inner) + std::vector::iterator &result) { // doing type check only once, here colvarvalue::check_types(x, *xv); std::list::iterator &xvi = xv; - std::vector::iterator &ii = inner; + std::vector::iterator &ii = result; switch (x.value_type) { case colvarvalue::type_scalar: cvm::error("Error: cannot calculate Legendre polynomials " "for scalar variables.\n"); break; - case colvarvalue::type_vector: + case colvarvalue::type_3vector: while (xvi != xv_end) { cvm::real const cosine = ((xvi)->rvector_value * x.rvector_value) / ((xvi)->rvector_value.norm() * x.rvector_value.norm()); xvi++; *(ii++) += 1.5*cosine*cosine - 0.5; } break; - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: while (xvi != xv_end) { cvm::real const cosine = (xvi++)->rvector_value * x.rvector_value; *(ii++) += 1.5*cosine*cosine - 0.5; } break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: while (xvi != xv_end) { - cvm::real const cosine = (xvi++)->quaternion_value.cosine (x.quaternion_value); + cvm::real const cosine = (xvi++)->quaternion_value.cosine(x.quaternion_value); *(ii++) += 1.5*cosine*cosine - 0.5; } break; default: x.undef_op(); }; } -std::ostream & operator << (std::ostream &os, colvarvalue const &x) -{ - switch (x.type()) { - case colvarvalue::type_scalar: - os << x.real_value; - break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - os << x.rvector_value; - break; - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - os << x.quaternion_value; - break; - case colvarvalue::type_notset: - os << "not set"; break; - } - return os; -} - - -std::ostream & operator << (std::ostream &os, std::vector const &v) -{ - for (size_t i = 0; i < v.size(); i++) { - os << v[i]; - } - return os; -} - - -std::istream & operator >> (std::istream &is, colvarvalue &x) -{ - if (x.type() == colvarvalue::type_notset) { - cvm::error("Trying to read from a stream a colvarvalue, " - "which has not yet been assigned a data type.\n"); - return is; - } - - switch (x.type()) { - case colvarvalue::type_scalar: - is >> x.real_value; - break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvectorderiv: - is >> x.rvector_value; - break; - case colvarvalue::type_unitvector: - is >> x.rvector_value; - x.apply_constraints(); - break; - case colvarvalue::type_quaternion: - is >> x.quaternion_value; - x.apply_constraints(); - break; - case colvarvalue::type_quaternionderiv: - is >> x.quaternion_value; - break; - default: - x.undef_op(); - } - return is; -} - - -size_t colvarvalue::output_width(size_t const &real_width) const -{ - switch (this->value_type) { - case colvarvalue::type_scalar: - return real_width; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return cvm::rvector::output_width(real_width); - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - return cvm::quaternion::output_width(real_width); - case colvarvalue::type_notset: - default: - return 0; - } -} - diff --git a/lib/colvars/colvarvalue.h b/lib/colvars/colvarvalue.h index 20c960259..f91cb840f 100644 --- a/lib/colvars/colvarvalue.h +++ b/lib/colvars/colvarvalue.h @@ -1,797 +1,934 @@ /// -*- c++ -*- #ifndef COLVARVALUE_H #define COLVARVALUE_H #include "colvarmodule.h" +#include "colvartypes.h" /// \brief Value of a collective variable: this is a metatype which /// can be set at runtime. By default it is set to be a scalar -/// number, and can be treated like that in all operations (this is +/// number, and can be treated as such in all operations (this is /// done by most \link cvc \endlink implementations). /// /// \link colvarvalue \endlink allows \link colvar \endlink to be /// treat different data types. By default, a \link colvarvalue -/// \endlink variable is a scalar number. If you want to use it as -/// another type, you should declare and initialize a variable as -/// \code colvarvalue x (colvarvalue::type_xxx); \endcode where -/// type_xxx is a value within the \link Type \endlink enum. -/// Alternatively, initialize x with \link x.type -/// (colvarvalue::type_xxx) \endlink at a later stage. +/// \endlink variable is a scalar number. To use it as +/// another type, declare and initialize it as +/// \code colvarvalue x(colvarvalue::type_xxx)\endcode, use \link x.type +/// (colvarvalue::type_xxx) \endlink at a later stage, or if unset, +/// assign the type with \code x = y; \endcode, provided y is correctly set. /// -/// Given a colvarvalue variable x which is not yet assigned (and -/// thus has not yet a type) it is also possible to correctly assign -/// the type with \code x = y; \endcode if y is correctly set. -/// Otherwise, an error will be raised if the \link Type \endlink of x -/// is different from the \link Type \endlink of y. -/// -/// Also, every operator (either unary or binary) on a \link +/// All operators (either unary or binary) on a \link /// colvarvalue \endlink object performs one or more checks on the -/// \link Type \endlink to avoid errors such as initializing a -/// three-dimensional vector with a scalar number (legal otherwise). -/// -/// \b Special \b case: when reading from a stream, there is no way to -/// detect the \link Type \endlink and safely handle errors at the -/// same time. Hence, when using \code is >> x; \endcode x \b MUST +/// \link Type \endlink, except when reading from a stream, when there is no way to +/// detect the \link Type \endlink. To use \code is >> x; \endcode x \b MUST /// already have a type correcly set up for properly parsing the -/// stream. An error will be raised otherwise. Usually this is not -/// the problem, because \link colvarvalue \endlink objects are first -/// initialized in the configuration, and the stream operation will be -/// performed only when reading restart files. -/// -/// No problem of course with the output streams: \code os << x; -/// \endcode will print a different output according to the value of -/// colvarvalue::value_type, and the width of such output is returned -/// by colvarvalue::output_width() +/// stream. No problem of course with the output streams: \code os << x; \endcode /// -/// \em Note \em on \em performance: at every operation between two -/// \link colvarvalue \endlink objects, their two \link Type \endlink -/// flags will be checked for a match. In a long array of \link -/// colvarvalue \endlink objects this is time consuming: a few static -/// functions are defined ("xxx_opt" functions) within the \link -/// colvarvalue \endlink class, which only check the matching once for -/// a large array, and execute different loops according to the type. -/// You should do the same for every time consuming loop involving -/// operations on \link colvarvalue \endlink objects if you want -/// e.g. to optimize your colvar bias. +/// \em Note \em on \em performance: to avoid type checks in a long array of \link +/// colvarvalue \endlink objects, use one of the existing "_opt" functions or implement a new one + class colvarvalue { public: /// \brief Possible types of value /// /// These three cover most possibilities of data type one can /// devise. If you need to implement a new colvar with a very /// complex data type, it's better to put an allocatable class here enum Type { /// Undefined type type_notset, /// Scalar number, implemented as \link colvarmodule::real \endlink (default) type_scalar, /// 3-dimensional vector, implemented as \link colvarmodule::rvector \endlink - type_vector, + type_3vector, /// 3-dimensional unit vector, implemented as \link colvarmodule::rvector \endlink - type_unitvector, + type_unit3vector, /// 3-dimensional vector that is a derivative of a unitvector - type_unitvectorderiv, + type_unit3vectorderiv, /// 4-dimensional unit vector representing a rotation, implemented as \link colvarmodule::quaternion \endlink type_quaternion, /// 4-dimensional vector that is a derivative of a quaternion type_quaternionderiv, - /// bogus type to hold the size of the enum + /// vector (arbitrary dimension) + type_vector, + /// Needed to iterate through enum type_all }; - /// Runtime description of value types - std::string static const type_desc[colvarvalue::type_all+1]; - /// User keywords for specifying value types - std::string static const type_keyword[colvarvalue::type_all+1]; - /// Number of degrees of freedom for each type - size_t static const dof_num[ colvarvalue::type_all+1]; + /// Current type of this colvarvalue object + Type value_type; /// \brief Real data member - cvm::real real_value; + cvm::real real_value; - /// \brief Vector data member - cvm::rvector rvector_value; + /// \brief 3-dimensional vector data member + cvm::rvector rvector_value; /// \brief Quaternion data member cvm::quaternion quaternion_value; - /// Current type of this colvarvalue object - Type value_type; + /// \brief Generic vector data member + cvm::vector1d vector1d_value; + /// \brief If \link vector1d_value \endlink is a concatenation of colvarvalues, + /// keep track of the individual types + std::vector elem_types; + + /// \brief If \link vector1d_value \endlink is a concatenation of colvarvalues, + /// these mark the initial components of each colvarvalue + std::vector elem_indices; + + /// \brief If \link vector1d_value \endlink is a concatenation of colvarvalues, + /// these mark how many components for each colvarvalue + std::vector elem_sizes; + + /// \brief Whether or not the type check is enforced static inline bool type_checking() { return true; } + /// Runtime description of value types + static std::string const type_desc(Type t); + + /// User keywords for specifying value types in the configuration + static std::string const type_keyword(Type t); + + /// Number of degrees of freedom for each supported type + static size_t num_df(Type t); + + /// Number of dimensions for each supported type (used to allocate vector1d_value) + static size_t num_dimensions(Type t); + + /// Number of dimensions of this variable + size_t size() const; + /// \brief Default constructor: this class defaults to a scalar /// number and always behaves like it unless you change its type inline colvarvalue() - : real_value(0.0), value_type(type_scalar) + : value_type(type_scalar), real_value(0.0) {} /// Constructor from a type specification inline colvarvalue(Type const &vti) : value_type(vti) { reset(); } /// Copy constructor from real base type inline colvarvalue(cvm::real const &x) - : real_value(x), value_type(type_scalar) + : value_type(type_scalar), real_value(x) {} /// \brief Copy constructor from rvector base type (Note: this sets - /// automatically a type \link type_vector \endlink , if you want a - /// \link type_unitvector \endlink you must set it explicitly) + /// automatically a type \link type_3vector \endlink , if you want a + /// \link type_unit3vector \endlink you must set it explicitly) inline colvarvalue(cvm::rvector const &v) - : rvector_value(v), value_type(type_vector) + : value_type(type_3vector), rvector_value(v) {} /// \brief Copy constructor from rvector base type (additional - /// argument to make possible to choose a \link type_unitvector + /// argument to make possible to choose a \link type_unit3vector /// \endlink inline colvarvalue(cvm::rvector const &v, Type const &vti) - : rvector_value(v), value_type(vti) + : value_type(vti), rvector_value(v) {} /// \brief Copy constructor from quaternion base type inline colvarvalue(cvm::quaternion const &q) - : quaternion_value(q), value_type(type_quaternion) + : value_type(type_quaternion), quaternion_value(q) {} /// Copy constructor from another \link colvarvalue \endlink - inline colvarvalue(colvarvalue const &x) - : value_type(x.value_type) - { - reset(); + colvarvalue(colvarvalue const &x); - switch (x.value_type) { - case type_scalar: - real_value = x.real_value; - break; - case type_vector: - case type_unitvector: - rvector_value = x.rvector_value; - break; - case type_quaternion: - quaternion_value = x.quaternion_value; - break; - case type_notset: - default: - break; - } - } + /// Copy constructor from vector1d base type + colvarvalue(cvm::vector1d const &v, Type const &vti); /// Set to the null value for the data type currently defined void reset(); /// \brief If the variable has constraints (e.g. unitvector or /// quaternion), transform it to satisfy them; this function needs /// to be called only when the \link colvarvalue \endlink /// is calculated outside of \link cvc \endlink objects void apply_constraints(); /// Get the current type inline Type type() const { return value_type; } /// Set the type explicitly inline void type(Type const &vti) { + // reset the value based on the previous type reset(); + if ((value_type == type_vector) && (vti != type_vector)) { + vector1d_value.resize(0); + } value_type = vti; - reset(); } /// Set the type after another \link colvarvalue \endlink inline void type(colvarvalue const &x) { + // reset the value held from based on the previous type reset(); - value_type = x.value_type; - reset(); + if (x.type() == type_vector) { + vector1d_value.resize(x.vector1d_value.size()); + } else { + if (value_type == type_vector) { + vector1d_value.resize(0); + } + } + value_type = x.type(); } /// Make the type a derivative of the original type - /// (constraints do not apply on time derivatives of vector values) + /// (so that its constraints do not apply) inline void is_derivative(); /// Square norm of this colvarvalue cvm::real norm2() const; /// Norm of this colvarvalue inline cvm::real norm() const { return std::sqrt(this->norm2()); } /// \brief Return the value whose scalar product with this value is /// 1 inline colvarvalue inverse() const; /// Square distance between this \link colvarvalue \endlink and another cvm::real dist2(colvarvalue const &x2) const; /// Derivative with respect to this \link colvarvalue \endlink of the square distance colvarvalue dist2_grad(colvarvalue const &x2) const; /// Assignment operator (type of x is checked) colvarvalue & operator = (colvarvalue const &x); void operator += (colvarvalue const &x); void operator -= (colvarvalue const &x); void operator *= (cvm::real const &a); void operator /= (cvm::real const &a); + // Binary operators (return values) + friend colvarvalue operator + (colvarvalue const &x1, colvarvalue const &x2); + friend colvarvalue operator - (colvarvalue const &x1, colvarvalue const &x2); + friend colvarvalue operator * (colvarvalue const &x, cvm::real const &a); + friend colvarvalue operator * (cvm::real const &a, colvarvalue const &x); + friend colvarvalue operator / (colvarvalue const &x, cvm::real const &a); - // Casting operator + /// Inner product + friend cvm::real operator * (colvarvalue const &x1, colvarvalue const &x2); + + // Cast to scalar inline operator cvm::real() const { if (value_type != type_scalar) { - error_rside(type_scalar); + cvm::error("Error: trying to use a variable of type \""+ + type_desc(value_type)+"\" as one of type \""+ + type_desc(type_scalar)+"\".\n"); } return real_value; } - // Casting operator + // Cast to 3-vector inline operator cvm::rvector() const { - if ((value_type != type_vector) && - (value_type != type_unitvector) && - (value_type != type_unitvectorderiv)) { - error_rside(type_vector); + if ((value_type != type_3vector) && + (value_type != type_unit3vector) && + (value_type != type_unit3vectorderiv)) { + cvm::error("Error: trying to use a variable of type \""+ + type_desc(value_type)+"\" as one of type \""+ + type_desc(type_3vector)+"\".\n"); } return rvector_value; } - // Casting operator + // Cast to quaternion inline operator cvm::quaternion() const { if ((value_type != type_quaternion) && (value_type != type_quaternionderiv)) { - error_rside(type_quaternion); + cvm::error("Error: trying to use a variable of type \""+ + type_desc(value_type)+"\" as one of type \""+ + type_desc(type_quaternion)+"\".\n"); } return quaternion_value; } - /// Special case when the variable is a real number, and all operations are defined + // Create a n-dimensional vector from one of the basic types, or return the existing vector + cvm::vector1d const as_vector() const; + + + /// Whether this variable is a real number inline bool is_scalar() const { return (value_type == type_scalar); } + + /// Add an element to the vector (requires that type_vector is already set). + /// This is only needed to use this object as a vector of "complex" colvar values. + /// To use it instead as a plain n-dimensional vector, access vector1d_value directly. + void add_elem(colvarvalue const &x); + + /// Get a single colvarvalue out of elements of the vector + colvarvalue const get_elem(int const i_begin, int const i_end, Type const vt) const; + + /// Set elements of the vector from a single colvarvalue + void set_elem(int const i_begin, int const i_end, colvarvalue const &x); + + /// Get a single colvarvalue out of elements of the vector + colvarvalue const get_elem(int const icv) const; + + /// Set elements of the vector from a single colvarvalue + void set_elem(int const icv, colvarvalue const &x); + + /// Get a scalar number out of an element of the vector + inline cvm::real operator [] (int const i) const + { + if (vector1d_value.size() > 0) { + return vector1d_value[i]; + } else { + cvm::error("Error: trying to use as a vector a variable that is not initialized as such.\n"); + return 0.0; + } + } + + /// Use an element of the vector as a scalar number + inline cvm::real & operator [] (int const i) + { + if (vector1d_value.size() > 0) { + return vector1d_value[i]; + } else { + cvm::error("Error: trying to use as a vector a variable that is not initialized as such.\n"); + real_value = 0.0; + return real_value; + } + } + + /// Ensure that the two types are the same within a binary operator - void static check_types(colvarvalue const &x1, colvarvalue const &x2); + int static check_types(colvarvalue const &x1, colvarvalue const &x2); + + /// Ensure that the two types are the same within an assignment, or that the left side is type_notset + int static check_types_assign(Type const &vt1, Type const &vt2); /// Undefined operation void undef_op() const; - /// Trying to assign this \link colvarvalue \endlink object to - /// another object set with a different type - void error_lside(Type const &vt) const; - /// Trying to assign another \link colvarvalue \endlink object set - /// with a different type to this object - void error_rside(Type const &vt) const; + /// \brief Formatted output operator + friend std::ostream & operator << (std::ostream &os, colvarvalue const &q); + + /// \brief Formatted input operator + friend std::istream & operator >> (std::istream &is, colvarvalue &q); /// Give the number of characters required to output this /// colvarvalue, given the current type assigned and the number of /// characters for a real number size_t output_width(size_t const &real_width) const; + /// Formats value as a script-friendly string (space separated list) + std::string to_simple_string() const; + + /// Parses value from a script-friendly string (space separated list) + int from_simple_string(std::string const &s); + - // optimized routines for operations with an array; xv and inner as - // vectors are assumed to have the same number of elements (i.e. the - // end for inner comes together with xv_end in the loop) + // optimized routines for operations on arrays of colvar values; + // xv and result are assumed to have the same number of elements /// \brief Optimized routine for the inner product of one collective /// variable with an array void static inner_opt(colvarvalue const &x, std::vector::iterator &xv, std::vector::iterator const &xv_end, - std::vector::iterator &inner); + std::vector::iterator &result); /// \brief Optimized routine for the inner product of one collective /// variable with an array void static inner_opt(colvarvalue const &x, std::list::iterator &xv, std::list::iterator const &xv_end, - std::vector::iterator &inner); + std::vector::iterator &result); /// \brief Optimized routine for the second order Legendre /// polynomial, (3cos^2(w)-1)/2, of one collective variable with an /// array void static p2leg_opt(colvarvalue const &x, std::vector::iterator &xv, std::vector::iterator const &xv_end, - std::vector::iterator &inner); + std::vector::iterator &result); /// \brief Optimized routine for the second order Legendre /// polynomial of one collective variable with an array void static p2leg_opt(colvarvalue const &x, std::list::iterator &xv, std::list::iterator const &xv_end, - std::vector::iterator &inner); + std::vector::iterator &result); }; -inline void colvarvalue::reset() +inline std::string const colvarvalue::type_desc(Type t) { - switch (value_type) { + switch (t) { case colvarvalue::type_scalar: - real_value = cvm::real(0.0); - break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - rvector_value = cvm::rvector(0.0, 0.0, 0.0); - break; + return "scalar number"; break; + case colvarvalue::type_3vector: + return "3-dimensional vector"; break; + case colvarvalue::type_unit3vector: + return "3-dimensional unit vector"; break; + case colvarvalue::type_unit3vectorderiv: + return "derivative of a 3-dimensional unit vector"; break; case colvarvalue::type_quaternion: + return "4-dimensional unit quaternion"; break; case colvarvalue::type_quaternionderiv: - quaternion_value = cvm::quaternion(0.0, 0.0, 0.0, 0.0); - break; + return "4-dimensional tangent vector"; break; + case colvarvalue::type_vector: + return "n-dimensional vector"; break; case colvarvalue::type_notset: + // fallthrough default: - break; + return "not set"; break; } } -inline void colvarvalue::apply_constraints() +inline std::string const colvarvalue::type_keyword(Type t) { - switch (value_type) { + switch (t) { + case colvarvalue::type_notset: + default: + return "not_set"; break; case colvarvalue::type_scalar: - case colvarvalue::type_vector: - case colvarvalue::type_unitvectorderiv: + return "scalar"; break; + case colvarvalue::type_3vector: + return "vector3"; break; + case colvarvalue::type_unit3vector: + return "unit_vector3"; break; + case colvarvalue::type_unit3vectorderiv: + return ""; break; + case colvarvalue::type_quaternion: + return "unit_quaternion"; break; case colvarvalue::type_quaternionderiv: - break; - case colvarvalue::type_unitvector: - rvector_value /= std::sqrt(rvector_value.norm2()); - break; + return ""; break; + case colvarvalue::type_vector: + return "vector"; break; + } +} + + +inline size_t colvarvalue::num_df(Type t) +{ + switch (t) { + case colvarvalue::type_notset: + default: + return 0; break; + case colvarvalue::type_scalar: + return 1; break; + case colvarvalue::type_3vector: + return 3; break; + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return 2; break; case colvarvalue::type_quaternion: - quaternion_value /= std::sqrt(quaternion_value.norm2()); - break; + case colvarvalue::type_quaternionderiv: + return 3; break; + case colvarvalue::type_vector: + // the size of a vector is unknown without its object + return 0; break; + } +} + + +inline size_t colvarvalue::num_dimensions(Type t) +{ + switch (t) { case colvarvalue::type_notset: default: - break; + return 0; break; + case colvarvalue::type_scalar: + return 1; break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return 3; break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return 4; break; + case colvarvalue::type_vector: + // the size of a vector is unknown without its object + return 0; break; } } -inline void colvarvalue::is_derivative() +inline size_t colvarvalue::size() const { switch (value_type) { + case colvarvalue::type_notset: + default: + return 0; break; case colvarvalue::type_scalar: - case colvarvalue::type_vector: - case colvarvalue::type_unitvectorderiv: + return 1; break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return 3; break; + case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: + return 4; break; + case colvarvalue::type_vector: + return vector1d_value.size(); break; + } +} + + +inline colvarvalue::colvarvalue(colvarvalue const &x) + : value_type(x.type()) +{ + switch (x.type()) { + case type_scalar: + real_value = x.real_value; break; - case colvarvalue::type_unitvector: - type(colvarvalue::type_unitvectorderiv); + case type_3vector: + case type_unit3vector: + case type_unit3vectorderiv: + rvector_value = x.rvector_value; break; - case colvarvalue::type_quaternion: - type(colvarvalue::type_quaternionderiv); + case type_quaternion: + case type_quaternionderiv: + quaternion_value = x.quaternion_value; break; - case colvarvalue::type_notset: + case type_vector: + vector1d_value = x.vector1d_value; + elem_types = x.elem_types; + elem_indices = x.elem_indices; + elem_sizes = x.elem_sizes; + case type_notset: default: break; } } +inline colvarvalue::colvarvalue(cvm::vector1d const &v, Type const &vti) +{ + if ((vti != type_vector) && (v.size() != num_dimensions(vti))) { + cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+ + "\" using a vector of size "+cvm::to_str(v.size())+ + ".\n"); + value_type = type_notset; + } else { + value_type = vti; + switch (vti) { + case type_scalar: + real_value = v[0]; + break; + case type_3vector: + case type_unit3vector: + case type_unit3vectorderiv: + rvector_value = cvm::rvector(v); + break; + case type_quaternion: + case type_quaternionderiv: + quaternion_value = cvm::quaternion(v); + break; + case type_vector: + vector1d_value = v; + break; + case type_notset: + default: + break; + } + } +} -inline cvm::real colvarvalue::norm2() const +inline int colvarvalue::check_types(colvarvalue const &x1, + colvarvalue const &x2) { - switch (value_type) { - case colvarvalue::type_scalar: - return (this->real_value)*(this->real_value); - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return (this->rvector_value).norm2(); - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - return (this->quaternion_value).norm2(); - case colvarvalue::type_notset: - default: - return 0.0; + if (!colvarvalue::type_checking()) { + return COLVARS_OK; } + + if (x1.type() != x2.type()) { + if (((x1.type() == type_unit3vector) && + (x2.type() == type_unit3vectorderiv)) || + ((x2.type() == type_unit3vector) && + (x1.type() == type_unit3vectorderiv)) || + ((x1.type() == type_quaternion) && + (x2.type() == type_quaternionderiv)) || + ((x2.type() == type_quaternion) && + (x1.type() == type_quaternionderiv))) { + return COLVARS_OK; + } else { + cvm::error("Trying to perform an operation between two colvar " + "values with different types, \""+ + colvarvalue::type_desc(x1.type())+ + "\" and \""+ + colvarvalue::type_desc(x2.type())+ + "\".\n"); + return COLVARS_ERROR; + } + } + + if (x1.type() == type_vector) { + if (x1.vector1d_value.size() != x2.vector1d_value.size()) { + cvm::error("Trying to perform an operation between two vector colvar " + "values with different sizes, "+ + cvm::to_str(x1.vector1d_value.size())+ + " and "+ + cvm::to_str(x2.vector1d_value.size())+ + ".\n"); + return COLVARS_ERROR; + } + } + return COLVARS_OK; } -inline colvarvalue colvarvalue::inverse() const +inline int colvarvalue::check_types_assign(colvarvalue::Type const &vt1, + colvarvalue::Type const &vt2) { - switch (value_type) { - case colvarvalue::type_scalar: - return colvarvalue(1.0/real_value); - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return colvarvalue(cvm::rvector(1.0/rvector_value.x, - 1.0/rvector_value.y, - 1.0/rvector_value.z)); - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - return colvarvalue(cvm::quaternion(1.0/quaternion_value.q0, - 1.0/quaternion_value.q1, - 1.0/quaternion_value.q2, - 1.0/quaternion_value.q3)); - case colvarvalue::type_notset: - default: - undef_op(); + if (!colvarvalue::type_checking()) { + return COLVARS_OK; } - return colvarvalue(); + + if (vt1 != type_notset) { + if (vt1 != vt2) { + cvm::error("Trying to assign a colvar value with type \""+ + type_desc(vt2)+"\" to one with type \""+ + type_desc(vt1)+"\".\n"); + return COLVARS_ERROR; + } + } + return COLVARS_OK; } -inline colvarvalue & colvarvalue::operator = (colvarvalue const &x) + +inline void colvarvalue::undef_op() const { - if (this->value_type != type_notset) - if (this->value_type != x.value_type) - error_lside(x.value_type); + cvm::error("Error: Undefined operation on a colvar of type \""+ + type_desc(this->type())+"\".\n"); +} - this->value_type = x.value_type; - switch (this->value_type) { +inline colvarvalue & colvarvalue::operator = (colvarvalue const &x) +{ + check_types_assign(this->type(), x.type()); + value_type = x.type(); + + switch (this->type()) { case colvarvalue::type_scalar: this->real_value = x.real_value; break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: this->rvector_value = x.rvector_value; break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: this->quaternion_value = x.quaternion_value; break; + case colvarvalue::type_vector: + vector1d_value = x.vector1d_value; + elem_types = x.elem_types; + elem_indices = x.elem_indices; + elem_sizes = x.elem_sizes; + break; case colvarvalue::type_notset: default: undef_op(); break; } return *this; } + inline void colvarvalue::operator += (colvarvalue const &x) { - if (colvarvalue::type_checking()) - colvarvalue::check_types(*this, x); + colvarvalue::check_types(*this, x); - switch (this->value_type) { + switch (this->type()) { case colvarvalue::type_scalar: this->real_value += x.real_value; break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: this->rvector_value += x.rvector_value; break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: this->quaternion_value += x.quaternion_value; break; + case colvarvalue::type_vector: + this->vector1d_value += x.vector1d_value; + break; case colvarvalue::type_notset: default: undef_op(); } } inline void colvarvalue::operator -= (colvarvalue const &x) { - if (colvarvalue::type_checking()) - colvarvalue::check_types(*this, x); + colvarvalue::check_types(*this, x); switch (value_type) { case colvarvalue::type_scalar: real_value -= x.real_value; break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: rvector_value -= x.rvector_value; break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: quaternion_value -= x.quaternion_value; break; + case colvarvalue::type_vector: + this->vector1d_value -= x.vector1d_value; + break; case colvarvalue::type_notset: default: undef_op(); } } + inline void colvarvalue::operator *= (cvm::real const &a) { switch (value_type) { case colvarvalue::type_scalar: real_value *= a; break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vectorderiv: rvector_value *= a; break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: quaternion_value *= a; break; + case colvarvalue::type_vector: + this->vector1d_value *= a; + break; case colvarvalue::type_notset: default: undef_op(); } } + inline void colvarvalue::operator /= (cvm::real const &a) { switch (value_type) { case colvarvalue::type_scalar: real_value /= a; break; - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: rvector_value /= a; break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: quaternion_value /= a; break; + case colvarvalue::type_vector: + this->vector1d_value /= a; + break; case colvarvalue::type_notset: default: undef_op(); } } -// binary operations between two colvarvalues - -inline colvarvalue operator + (colvarvalue const &x1, - colvarvalue const &x2) +inline cvm::vector1d const colvarvalue::as_vector() const { - if (colvarvalue::type_checking()) - colvarvalue::check_types(x1, x2); - - switch (x1.value_type) { + switch (value_type) { case colvarvalue::type_scalar: - return colvarvalue(x1.real_value + x2.real_value); - case colvarvalue::type_vector: - return colvarvalue(x1.rvector_value + x2.rvector_value); - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return colvarvalue(x1.rvector_value + x2.rvector_value, - colvarvalue::type_unitvector); + { + cvm::vector1d v(1); + v[0] = real_value; + return v; + } + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return rvector_value.as_vector(); case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: - return colvarvalue(x1.quaternion_value + x2.quaternion_value); - case colvarvalue::type_notset: - default: - x1.undef_op(); - return colvarvalue(colvarvalue::type_notset); - }; -} - -inline colvarvalue operator - (colvarvalue const &x1, - colvarvalue const &x2) -{ - if (colvarvalue::type_checking()) - colvarvalue::check_types(x1, x2); - - switch (x1.value_type) { - case colvarvalue::type_scalar: - return colvarvalue(x1.real_value - x2.real_value); + return quaternion_value.as_vector(); case colvarvalue::type_vector: - return colvarvalue(x1.rvector_value - x2.rvector_value); - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return colvarvalue(x1.rvector_value - x2.rvector_value, - colvarvalue::type_unitvector); - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - return colvarvalue(x1.quaternion_value - x2.quaternion_value); + return vector1d_value; + case colvarvalue::type_notset: default: - x1.undef_op(); - return colvarvalue(colvarvalue::type_notset); - }; + return cvm::vector1d(0); + } } -// binary operations with real numbers - -inline colvarvalue operator * (cvm::real const &a, - colvarvalue const &x) +inline void colvarvalue::reset() { - switch (x.value_type) { + switch (value_type) { case colvarvalue::type_scalar: - return colvarvalue(a * x.real_value); - case colvarvalue::type_vector: - return colvarvalue(a * x.rvector_value); - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return colvarvalue(a * x.rvector_value, - colvarvalue::type_unitvector); + real_value = 0.0; + break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + rvector_value.reset(); + break; case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: - return colvarvalue(a * x.quaternion_value); + quaternion_value.reset(); + break; + case colvarvalue::type_vector: + vector1d_value.reset(); + break; case colvarvalue::type_notset: default: - x.undef_op(); - return colvarvalue(colvarvalue::type_notset); + break; } } -inline colvarvalue operator * (colvarvalue const &x, - cvm::real const &a) + +inline void colvarvalue::apply_constraints() { - switch (x.value_type) { + switch (value_type) { case colvarvalue::type_scalar: - return colvarvalue(x.real_value * a); - case colvarvalue::type_vector: - return colvarvalue(x.rvector_value * a); - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return colvarvalue(x.rvector_value * a, - colvarvalue::type_unitvector); - case colvarvalue::type_quaternion: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vectorderiv: case colvarvalue::type_quaternionderiv: - return colvarvalue(x.quaternion_value * a); + break; + case colvarvalue::type_unit3vector: + rvector_value /= std::sqrt(rvector_value.norm2()); + break; + case colvarvalue::type_quaternion: + quaternion_value /= std::sqrt(quaternion_value.norm2()); + break; + case colvarvalue::type_vector: + if (elem_types.size() > 0) { + // if we have information about non-scalar types, use it + size_t i; + for (i = 0; i < elem_types.size(); i++) { + if (elem_sizes[i] == 1) continue; // TODO this can be optimized further + colvarvalue cvtmp(vector1d_value.slice(elem_indices[i], + elem_indices[i] + elem_sizes[i]), elem_types[i]); + cvtmp.apply_constraints(); + set_elem(i, cvtmp); + } + } + break; case colvarvalue::type_notset: default: - x.undef_op(); - return colvarvalue(colvarvalue::type_notset); + break; } } -inline colvarvalue operator / (colvarvalue const &x, - cvm::real const &a) + +inline void colvarvalue::is_derivative() { - switch (x.value_type) { + switch (value_type) { case colvarvalue::type_scalar: - return colvarvalue(x.real_value / a); - case colvarvalue::type_vector: - return colvarvalue(x.rvector_value / a); - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return colvarvalue(x.rvector_value / a, - colvarvalue::type_unitvector); - case colvarvalue::type_quaternion: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vectorderiv: case colvarvalue::type_quaternionderiv: - return colvarvalue(x.quaternion_value / a); + break; + case colvarvalue::type_unit3vector: + type(colvarvalue::type_unit3vectorderiv); + break; + case colvarvalue::type_quaternion: + type(colvarvalue::type_quaternionderiv); + break; + case colvarvalue::type_vector: + // TODO + break; case colvarvalue::type_notset: default: - x.undef_op(); - return colvarvalue(colvarvalue::type_notset); + break; } } -// inner product between two colvarvalues - -inline cvm::real operator * (colvarvalue const &x1, - colvarvalue const &x2) +inline cvm::real colvarvalue::norm2() const { - if (colvarvalue::type_checking()) - colvarvalue::check_types(x1, x2); - - switch (x1.value_type) { + switch (value_type) { case colvarvalue::type_scalar: - return (x1.real_value * x2.real_value); - case colvarvalue::type_vector: - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - return (x1.rvector_value * x2.rvector_value); + return (this->real_value)*(this->real_value); + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return (this->rvector_value).norm2(); case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: - // the "*" product is the quaternion product, here the inner - // member function is used instead - return (x1.quaternion_value.inner(x2.quaternion_value)); + return (this->quaternion_value).norm2(); + case colvarvalue::type_vector: + if (elem_types.size() > 0) { + // if we have information about non-scalar types, use it + cvm::real result = 0.0; + size_t i; + for (i = 0; i < elem_types.size(); i++) { + result += (this->get_elem(i)).norm2(); + } + return result; + } else { + return vector1d_value.norm2(); + } + break; case colvarvalue::type_notset: default: - x1.undef_op(); return 0.0; - }; + } } - inline cvm::real colvarvalue::dist2(colvarvalue const &x2) const { - if (colvarvalue::type_checking()) - colvarvalue::check_types(*this, x2); + colvarvalue::check_types(*this, x2); - switch (this->value_type) { + switch (this->type()) { case colvarvalue::type_scalar: return (this->real_value - x2.real_value)*(this->real_value - x2.real_value); - case colvarvalue::type_vector: + case colvarvalue::type_3vector: return (this->rvector_value - x2.rvector_value).norm2(); - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: // angle between (*this) and x2 is the distance return std::acos(this->rvector_value * x2.rvector_value) * std::acos(this->rvector_value * x2.rvector_value); case colvarvalue::type_quaternion: case colvarvalue::type_quaternionderiv: // angle between (*this) and x2 is the distance, the quaternion // object has it implemented internally return this->quaternion_value.dist2(x2.quaternion_value); - case colvarvalue::type_notset: - default: - this->undef_op(); - return 0.0; - }; -} - - -inline colvarvalue colvarvalue::dist2_grad(colvarvalue const &x2) const -{ - if (colvarvalue::type_checking()) - colvarvalue::check_types(*this, x2); - - switch (this->value_type) { - case colvarvalue::type_scalar: - return 2.0 * (this->real_value - x2.real_value); case colvarvalue::type_vector: - return 2.0 * (this->rvector_value - x2.rvector_value); - case colvarvalue::type_unitvector: - case colvarvalue::type_unitvectorderiv: - { - cvm::rvector const &v1 = this->rvector_value; - cvm::rvector const &v2 = x2.rvector_value; - cvm::real const cos_t = v1 * v2; - cvm::real const sin_t = std::sqrt(1.0 - cos_t*cos_t); - return colvarvalue( 2.0 * sin_t * - cvm::rvector((-1.0) * sin_t * v2.x + - cos_t/sin_t * (v1.x - cos_t*v2.x), - (-1.0) * sin_t * v2.y + - cos_t/sin_t * (v1.y - cos_t*v2.y), - (-1.0) * sin_t * v2.z + - cos_t/sin_t * (v1.z - cos_t*v2.z) - ), - colvarvalue::type_unitvector ); - } - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - return this->quaternion_value.dist2_grad(x2.quaternion_value); + return (this->vector1d_value - x2.vector1d_value).norm2(); case colvarvalue::type_notset: default: this->undef_op(); - return colvarvalue(colvarvalue::type_notset); + return 0.0; }; } -inline void colvarvalue::check_types(colvarvalue const &x1, - colvarvalue const &x2) -{ - if (x1.value_type != x2.value_type) { - if (((x1.value_type == type_unitvector) && - (x2.value_type == type_unitvectorderiv)) || - ((x2.value_type == type_unitvector) && - (x1.value_type == type_unitvectorderiv)) || - ((x1.value_type == type_quaternion) && - (x2.value_type == type_quaternionderiv)) || - ((x2.value_type == type_quaternion) && - (x1.value_type == type_quaternionderiv))) { - return; - } - cvm::error("Performing an operation between two colvar " - "values with different types, \""+ - colvarvalue::type_desc[x1.value_type]+ - "\" and \""+ - colvarvalue::type_desc[x2.value_type]+ - "\".\n"); - } -} - - -std::ostream & operator << (std::ostream &os, colvarvalue const &x); -std::ostream & operator << (std::ostream &os, std::vector const &v); - -std::istream & operator >> (std::istream &is, colvarvalue &x); - - #endif