diff --git a/doc/src/PDF/colvars-refman-lammps.pdf b/doc/src/PDF/colvars-refman-lammps.pdf index 657f24c436..0dd82d4794 100644 Binary files a/doc/src/PDF/colvars-refman-lammps.pdf and b/doc/src/PDF/colvars-refman-lammps.pdf differ diff --git a/lib/colvars/colvar.cpp b/lib/colvars/colvar.cpp index 344a9a1301..49f0285091 100644 --- a/lib/colvars/colvar.cpp +++ b/lib/colvars/colvar.cpp @@ -43,7 +43,8 @@ colvar::colvar(std::string const &conf) kinetic_energy = 0.0; potential_energy = 0.0; - cvm::combine_errors(error_code, init_components(conf)); + error_code |= init_components(conf); + if (error_code != COLVARS_OK) return; size_t i; @@ -492,110 +493,44 @@ int colvar::init_components(std::string const &conf) { int error_code = COLVARS_OK; - cvm::combine_errors(error_code, - init_components_type(conf, - "distance", "distance")); - cvm::combine_errors(error_code, - init_components_type(conf, - "distance vector", "distanceVec")); - cvm::combine_errors(error_code, - init_components_type(conf, - "Cartesian coordinates", "cartesian")); - cvm::combine_errors(error_code, - init_components_type(conf, - "distance vector " - "direction", "distanceDir")); - cvm::combine_errors(error_code, - init_components_type(conf, - "distance projection " - "on an axis", "distanceZ")); - cvm::combine_errors(error_code, - init_components_type(conf, - "distance projection " - "on a plane", "distanceXY")); - cvm::combine_errors(error_code, - init_components_type(conf, - "average distance " - "weighted by inverse power", - "distanceInv")); - cvm::combine_errors(error_code, - init_components_type(conf, - "N1xN2-long vector " - "of pairwise distances", - "distancePairs")); - - cvm::combine_errors(error_code, - init_components_type(conf, - "coordination " - "number", "coordNum")); - cvm::combine_errors(error_code, - init_components_type(conf, - "self-coordination " - "number", "selfCoordNum")); - - cvm::combine_errors(error_code, - init_components_type(conf, - "angle", "angle")); - cvm::combine_errors(error_code, - init_components_type(conf, - "dipole angle", "dipoleAngle")); - cvm::combine_errors(error_code, - init_components_type(conf, - "dihedral", "dihedral")); - - cvm::combine_errors(error_code, - init_components_type(conf, - "hydrogen bond", "hBond")); - - // cvm::combine_errors(error_code, init_components_type(conf, "alpha helix", "alphaDihedrals")); - cvm::combine_errors(error_code, - init_components_type(conf, - "alpha helix", "alpha")); - - cvm::combine_errors(error_code, - init_components_type(conf, - "dihedral " - "principal component", "dihedralPC")); - - cvm::combine_errors(error_code, - init_components_type(conf, - "orientation", "orientation")); - cvm::combine_errors(error_code, - init_components_type(conf, - "orientation " - "angle", "orientationAngle")); - cvm::combine_errors(error_code, - init_components_type(conf, - "orientation " - "projection", "orientationProj")); - cvm::combine_errors(error_code, - init_components_type(conf, - "tilt", "tilt")); - cvm::combine_errors(error_code, - init_components_type(conf, - "spin angle", "spinAngle")); - - cvm::combine_errors(error_code, - init_components_type(conf, - "RMSD", "rmsd")); - - // cvm::combine_errors(error_code, init_components_type (conf,"logarithm of MSD", "logmsd")); - - cvm::combine_errors(error_code, - init_components_type(conf, - "radius of " - "gyration", "gyration")); - cvm::combine_errors(error_code, - init_components_type(conf, - "moment of " - "inertia", "inertia")); - cvm::combine_errors(error_code, - init_components_type(conf, - "moment of inertia around an axis", - "inertiaZ")); - cvm::combine_errors(error_code, - init_components_type(conf, - "eigenvector", "eigenvector")); + error_code |= init_components_type(conf, "distance", "distance"); + error_code |= init_components_type(conf, "distance vector", "distanceVec"); + error_code |= init_components_type(conf, "Cartesian coordinates", "cartesian"); + error_code |= init_components_type(conf, "distance vector " + "direction", "distanceDir"); + error_code |= init_components_type(conf, "distance projection " + "on an axis", "distanceZ"); + error_code |= init_components_type(conf, "distance projection " + "on a plane", "distanceXY"); + error_code |= init_components_type(conf, "average distance " + "weighted by inverse power", "distanceInv"); + error_code |= init_components_type(conf, "N1xN2-long vector " + "of pairwise distances", "distancePairs"); + error_code |= init_components_type(conf, "coordination " + "number", "coordNum"); + error_code |= init_components_type(conf, "self-coordination " + "number", "selfCoordNum"); + error_code |= init_components_type(conf, "angle", "angle"); + error_code |= init_components_type(conf, "dipole angle", "dipoleAngle"); + error_code |= init_components_type(conf, "dihedral", "dihedral"); + error_code |= init_components_type(conf, "hydrogen bond", "hBond"); + error_code |= init_components_type(conf, "alpha helix", "alpha"); + error_code |= init_components_type(conf, "dihedral " + "principal component", "dihedralPC"); + error_code |= init_components_type(conf, "orientation", "orientation"); + error_code |= init_components_type(conf, "orientation " + "angle", "orientationAngle"); + error_code |= init_components_type(conf, "orientation " + "projection", "orientationProj"); + error_code |= init_components_type(conf, "tilt", "tilt"); + error_code |= init_components_type(conf, "spin angle", "spinAngle"); + error_code |= init_components_type(conf, "RMSD", "rmsd"); + error_code |= init_components_type(conf, "radius of " + "gyration", "gyration"); + error_code |= init_components_type(conf, "moment of " + "inertia", "inertia"); + error_code |= init_components_type(conf, "moment of inertia around an axis", "inertiaZ"); + error_code |= init_components_type(conf, "eigenvector", "eigenvector"); if (!cvcs.size() || (error_code != COLVARS_OK)) { cvm::error("Error: no valid components were provided " @@ -732,7 +667,7 @@ int colvar::parse_analysis(std::string const &conf) } else { cvm::log("Unknown type of correlation function, \""+ acf_type_str+"\".\n"); - cvm::set_error_bit(INPUT_ERROR); + cvm::set_error_bits(INPUT_ERROR); } get_keyval(conf, "corrFuncOffset", acf_offset, 0); @@ -803,9 +738,11 @@ int colvar::calc() // Note: if anything is added here, it should be added also in the SMP block of calc_colvars() int error_code = COLVARS_OK; if (is_enabled(f_cv_active)) { - cvm::combine_errors(error_code, update_cvc_flags()); - cvm::combine_errors(error_code, calc_cvcs()); - cvm::combine_errors(error_code, collect_cvc_data()); + error_code |= update_cvc_flags(); + if (error_code != COLVARS_OK) return error_code; + error_code |= calc_cvcs(); + if (error_code != COLVARS_OK) return error_code; + error_code |= collect_cvc_data(); } return error_code; } @@ -818,15 +755,15 @@ int colvar::calc_cvcs(int first_cvc, size_t num_cvcs) cvm::log("Calculating colvar \""+this->name+"\", components "+ cvm::to_str(first_cvc)+" through "+cvm::to_str(first_cvc+num_cvcs)+".\n"); - cvm::combine_errors(error_code, check_cvc_range(first_cvc, num_cvcs)); + error_code |= check_cvc_range(first_cvc, num_cvcs); if (error_code != COLVARS_OK) { return error_code; } - cvm::combine_errors(error_code, calc_cvc_values(first_cvc, num_cvcs)); - cvm::combine_errors(error_code, calc_cvc_gradients(first_cvc, num_cvcs)); - cvm::combine_errors(error_code, calc_cvc_sys_forces(first_cvc, num_cvcs)); - cvm::combine_errors(error_code, calc_cvc_Jacobians(first_cvc, num_cvcs)); + error_code |= calc_cvc_values(first_cvc, num_cvcs); + error_code |= calc_cvc_gradients(first_cvc, num_cvcs); + error_code |= calc_cvc_sys_forces(first_cvc, num_cvcs); + error_code |= calc_cvc_Jacobians(first_cvc, num_cvcs); if (cvm::debug()) cvm::log("Done calculating colvar \""+this->name+"\".\n"); @@ -842,12 +779,11 @@ int colvar::collect_cvc_data() int error_code = COLVARS_OK; - cvm::combine_errors(error_code, collect_cvc_values()); - cvm::combine_errors(error_code, collect_cvc_gradients()); - cvm::combine_errors(error_code, collect_cvc_sys_forces()); - cvm::combine_errors(error_code, collect_cvc_Jacobians()); - - cvm::combine_errors(error_code, calc_colvar_properties()); + error_code |= collect_cvc_values(); + error_code |= collect_cvc_gradients(); + error_code |= collect_cvc_sys_forces(); + error_code |= collect_cvc_Jacobians(); + error_code |= calc_colvar_properties(); if (cvm::debug()) cvm::log("Done calculating colvar \""+this->name+"\"'s properties.\n"); @@ -1374,7 +1310,7 @@ bool colvar::periodic_boundaries(colvarvalue const &lb, colvarvalue const &ub) c if ( (!is_enabled(f_cv_lower_boundary)) || (!is_enabled(f_cv_upper_boundary)) ) { cvm::log("Error: checking periodicity for collective variable \""+this->name+"\" " "requires lower and upper boundaries to be defined.\n"); - cvm::set_error_bit(INPUT_ERROR); + cvm::set_error_bits(INPUT_ERROR); } if (period > 0.0) { diff --git a/lib/colvars/colvaratoms.cpp b/lib/colvars/colvaratoms.cpp index b77576e896..786a72821f 100644 --- a/lib/colvars/colvaratoms.cpp +++ b/lib/colvars/colvaratoms.cpp @@ -297,7 +297,7 @@ int cvm::atom_group::parse(std::string const &conf) std::string numbers_conf = ""; size_t pos = 0; while (key_lookup(group_conf, "atomNumbers", numbers_conf, pos)) { - cvm::combine_errors(parse_error, add_atom_numbers(numbers_conf)); + parse_error |= add_atom_numbers(numbers_conf); numbers_conf = ""; } } @@ -306,7 +306,7 @@ int cvm::atom_group::parse(std::string const &conf) std::string index_group_name; if (get_keyval(group_conf, "indexGroup", index_group_name)) { // use an index group from the index file read globally - cvm::combine_errors(parse_error, add_index_group(index_group_name)); + parse_error |= add_index_group(index_group_name); } } @@ -315,7 +315,7 @@ int cvm::atom_group::parse(std::string const &conf) size_t pos = 0; while (key_lookup(group_conf, "atomNumbersRange", range_conf, pos)) { - cvm::combine_errors(parse_error, add_atom_numbers_range(range_conf)); + parse_error |= add_atom_numbers_range(range_conf); range_conf = ""; } } @@ -342,8 +342,8 @@ int cvm::atom_group::parse(std::string const &conf) cvm::error("Error: more instances of \"atomNameResidueRange\" than " "values of \"psfSegID\".\n", INPUT_ERROR); } else { - cvm::combine_errors(parse_error, add_atom_name_residue_range(psf_segids.size() ? - *psii : std::string(""), range_conf)); + parse_error |= add_atom_name_residue_range(psf_segids.size() ? + *psii : std::string(""), range_conf); if (psf_segids.size()) psii++; } range_conf = ""; @@ -407,7 +407,7 @@ int cvm::atom_group::parse(std::string const &conf) index = (cvm::proxy)->init_atom_group(atoms_ids); } - cvm::combine_errors(parse_error, parse_fitting_options(group_conf)); + parse_error |= parse_fitting_options(group_conf); // TODO move this to colvarparse object check_keywords(group_conf, key.c_str()); diff --git a/lib/colvars/colvarbias.cpp b/lib/colvars/colvarbias.cpp index 90c552ac0b..073cfc3965 100644 --- a/lib/colvars/colvarbias.cpp +++ b/lib/colvars/colvarbias.cpp @@ -203,7 +203,7 @@ cvm::real colvarbias::energy_difference(std::string const &conf) } -// So far, these are only implemented in colvarsbias_abf +// So far, these are only implemented in colvarbias_abf int colvarbias::bin_num() { cvm::error("Error: bin_num() not implemented.\n"); diff --git a/lib/colvars/colvarbias_histogram.cpp b/lib/colvars/colvarbias_histogram.cpp index 542dde2017..15ad5936aa 100644 --- a/lib/colvars/colvarbias_histogram.cpp +++ b/lib/colvars/colvarbias_histogram.cpp @@ -104,7 +104,7 @@ int colvarbias_histogram::update() { int error_code = COLVARS_OK; // update base class - cvm::combine_errors(error_code, colvarbias::update()); + error_code |= colvarbias::update(); if (cvm::debug()) { cvm::log("Updating histogram bias " + this->name); @@ -157,7 +157,7 @@ int colvarbias_histogram::update() write_output_files(); } - cvm::combine_errors(error_code, cvm::get_error()); + error_code |= cvm::get_error(); return error_code; } diff --git a/lib/colvars/colvarcomp.cpp b/lib/colvars/colvarcomp.cpp index eec43d0963..89973516be 100644 --- a/lib/colvars/colvarcomp.cpp +++ b/lib/colvars/colvarcomp.cpp @@ -43,11 +43,7 @@ colvar::cvc::cvc(std::string const &conf) // All cvcs implement this provide(f_cvc_debug_gradient); - { - bool b_debug_gradient; - get_keyval(conf, "debugGradients", b_debug_gradient, false, parse_silent); - if (b_debug_gradient) enable(f_cvc_debug_gradient); - } + get_keyval(conf, "debugGradients", set_feature(f_cvc_debug_gradient), false, parse_silent); // Attempt scalable calculations when in parallel? (By default yes, if available) get_keyval(conf, "scalable", b_try_scalable, true); diff --git a/lib/colvars/colvardeps.cpp b/lib/colvars/colvardeps.cpp index eabb67de4c..2801abb191 100644 --- a/lib/colvars/colvardeps.cpp +++ b/lib/colvars/colvardeps.cpp @@ -215,7 +215,7 @@ void cvm::deps::init_cvb_requires() { // Initialize feature_states for each instance feature_states.reserve(f_cvb_ntot); for (i = 0; i < f_cvb_ntot; i++) { - feature_states.push_back(new feature_state(true, false)); + feature_states.push_back(new feature_state(this, feature_states.size(), true, false)); // Most features are available, so we set them so // and list exceptions below } @@ -319,7 +319,7 @@ void cvm::deps::init_cv_requires() { // Initialize feature_states for each instance feature_states.reserve(f_cv_ntot); for (i = 0; i < f_cv_ntot; i++) { - feature_states.push_back(new feature_state(true, false)); + feature_states.push_back(new feature_state(this, feature_states.size(), true, false)); // Most features are available, so we set them so // and list exceptions below } @@ -385,7 +385,7 @@ void cvm::deps::init_cvc_requires() { // default as unavailable, not enabled feature_states.reserve(f_cvc_ntot); for (i = 0; i < cvm::deps::f_cvc_ntot; i++) { - feature_states.push_back(new feature_state(false, false)); + feature_states.push_back(new feature_state(this, feature_states.size(), false, false)); } // Features that are implemented by all cvcs by default @@ -429,7 +429,7 @@ void cvm::deps::init_ag_requires() { // default as unavailable, not enabled feature_states.reserve(f_ag_ntot); for (i = 0; i < cvm::deps::f_ag_ntot; i++) { - feature_states.push_back(new feature_state(false, false)); + feature_states.push_back(new feature_state(this, feature_states.size(), false, false)); } // Features that are implemented (or not) by all atom groups diff --git a/lib/colvars/colvardeps.h b/lib/colvars/colvardeps.h index 8787819b45..2aed77be50 100644 --- a/lib/colvars/colvardeps.h +++ b/lib/colvars/colvardeps.h @@ -27,9 +27,16 @@ public: std::string description; // reference to object name (cv, cvc etc.) /// This contains the current state of each feature for each object - struct feature_state { - feature_state(bool a, bool e) - : available(a), enabled(e) {} + class feature_state { + private: + cvm::deps *const deps_object; + int const id; + operator int() {} // never cast as int + public: + inline cvm::deps *object() const { return deps_object; } + inline int feature_id() const { return id; } + feature_state(cvm::deps *o, int i, bool a, bool e) + : deps_object(o), id(i), available(a), enabled(e) {} /// Available means: supported, subject to dependencies as listed, /// MAY BE ENABLED AS A RESULT OF DEPENDENCY SOLVING @@ -48,6 +55,12 @@ public: /// List of the state of all features std::vector feature_states; + /// Allow setting a feature state while parsing its kewyord + inline feature_state * set_feature(int id) + { + return feature_states[id]; + } + /// Describes a feature and its dependecies /// used in a static array within each subclass class feature { diff --git a/lib/colvars/colvarmodule.cpp b/lib/colvars/colvarmodule.cpp index 9317c421ed..4537c09509 100644 --- a/lib/colvars/colvarmodule.cpp +++ b/lib/colvars/colvarmodule.cpp @@ -340,8 +340,8 @@ int colvarmodule::parse_biases(std::string const &conf) int colvarmodule::catch_input_errors(int result) { if (result != COLVARS_OK || get_error()) { - set_error_bit(result); - set_error_bit(INPUT_ERROR); + set_error_bits(result); + set_error_bits(INPUT_ERROR); parse->init(); return get_error(); } @@ -493,27 +493,27 @@ int colvarmodule::calc() cvm::to_str(cvm::step_absolute())+"\n"); } - combine_errors(error_code, calc_colvars()); + error_code |= calc_colvars(); // set biasing forces to zero before biases are calculated and summed over for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); cvi++) { (*cvi)->reset_bias_force(); } - combine_errors(error_code, calc_biases()); - combine_errors(error_code, update_colvar_forces()); + error_code |= calc_biases(); + error_code |= update_colvar_forces(); if (cvm::b_analysis) { - combine_errors(error_code, analyze()); + error_code |= analyze(); } // write trajectory files, if needed if (cv_traj_freq && cv_traj_name.size()) { - combine_errors(error_code, write_traj_files()); + error_code |= write_traj_files(); } // write restart files, if needed if (restart_out_freq && restart_out_name.size()) { - combine_errors(error_code, write_restart_files()); + error_code |= write_restart_files(); } return error_code; @@ -551,7 +551,7 @@ int colvarmodule::calc_colvars() for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { if (!(*cvi)->is_enabled()) continue; - combine_errors(error_code, (*cvi)->update_cvc_flags()); + error_code |= (*cvi)->update_cvc_flags(); size_t num_items = (*cvi)->num_active_cvcs(); colvars_smp.reserve(colvars_smp.size() + num_items); @@ -566,12 +566,12 @@ int colvarmodule::calc_colvars() cvm::decrease_depth(); // calculate colvar components in parallel - combine_errors(error_code, proxy->smp_colvars_loop()); + error_code |= proxy->smp_colvars_loop(); cvm::increase_depth(); for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { if (!(*cvi)->is_enabled()) continue; - combine_errors(error_code, (*cvi)->collect_cvc_data()); + error_code |= (*cvi)->collect_cvc_data(); } cvm::decrease_depth(); @@ -581,7 +581,7 @@ int colvarmodule::calc_colvars() cvm::increase_depth(); for (cvi = colvars.begin(); cvi != colvars.end(); cvi++) { if (!(*cvi)->is_enabled()) continue; - combine_errors(error_code, (*cvi)->calc()); + error_code |= (*cvi)->calc(); if (cvm::get_error()) { return COLVARS_ERROR; } @@ -589,7 +589,7 @@ int colvarmodule::calc_colvars() cvm::decrease_depth(); } - combine_errors(error_code, cvm::get_error()); + error_code |= cvm::get_error(); return error_code; } @@ -609,21 +609,21 @@ int colvarmodule::calc_biases() if (use_scripted_forces && !scripting_after_biases) { // calculate biases and scripted forces in parallel - combine_errors(error_code, proxy->smp_biases_script_loop()); + error_code |= proxy->smp_biases_script_loop(); } else { // calculate biases in parallel - combine_errors(error_code, proxy->smp_biases_loop()); + error_code |= proxy->smp_biases_loop(); } } else { if (use_scripted_forces && !scripting_after_biases) { - combine_errors(error_code, calc_scripted_forces()); + error_code |= calc_scripted_forces(); } cvm::increase_depth(); for (bi = biases.begin(); bi != biases.end(); bi++) { - combine_errors(error_code, (*bi)->update()); + error_code |= (*bi)->update(); if (cvm::get_error()) { return COLVARS_ERROR; } @@ -661,7 +661,7 @@ int colvarmodule::update_colvar_forces() cvm::decrease_depth(); if (use_scripted_forces && scripting_after_biases) { - combine_errors(error_code, calc_scripted_forces()); + error_code |= calc_scripted_forces(); } cvm::real total_colvar_energy = 0.0; @@ -913,17 +913,17 @@ int colvarmodule::setup_output() std::string("")); if (cv_traj_freq && cv_traj_name.size()) { - combine_errors(error_code, open_traj_file(cv_traj_name)); + error_code |= open_traj_file(cv_traj_name); } for (std::vector::iterator bi = biases.begin(); bi != biases.end(); bi++) { - combine_errors(error_code, (*bi)->setup_output()); + error_code |= (*bi)->setup_output(); } if (error_code != COLVARS_OK || cvm::get_error()) { - set_error_bit(FILE_ERROR); + set_error_bits(FILE_ERROR); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); @@ -1259,29 +1259,20 @@ size_t & cvm::depth() } -void colvarmodule::set_error_bit(int code) +void colvarmodule::set_error_bits(int code) { - if (code > 0) { - cvm::fatal_error("Error: set_error_bit() received positive error code.\n"); + if (code < 0) { + cvm::fatal_error("Error: set_error_bits() received negative error code.\n"); return; } proxy->smp_lock(); - errorCode = -1 * ((-1 * errorCode) | (-1 * code) | (-1 * COLVARS_ERROR)); + errorCode |= code | COLVARS_ERROR; proxy->smp_unlock(); } bool colvarmodule::get_error_bit(int code) { - return bool((-1 * errorCode) & (-1 * code)); -} - -void colvarmodule::combine_errors(int &target, int const code) -{ - if (code > 0 || target > 0) { - cvm::fatal_error("Error: combine_errors() received positive error code.\n"); - return; - } - target = -1 * ((-1 * target) | (-1 * code)); + return bool(errorCode & code); } void colvarmodule::clear_error() @@ -1294,7 +1285,7 @@ void colvarmodule::clear_error() void cvm::error(std::string const &message, int code) { - set_error_bit(code); + set_error_bits(code); proxy->error(message); } @@ -1303,7 +1294,7 @@ void cvm::fatal_error(std::string const &message) { // TODO once all non-fatal errors have been set to be handled by error(), // set DELETE_COLVARS here for VMD to handle it - set_error_bit(FATAL_ERROR); + set_error_bits(FATAL_ERROR); proxy->fatal_error(message); } diff --git a/lib/colvars/colvarmodule.h b/lib/colvars/colvarmodule.h index b8fc01be9e..516f968769 100644 --- a/lib/colvars/colvarmodule.h +++ b/lib/colvars/colvarmodule.h @@ -4,7 +4,7 @@ #define COLVARMODULE_H #ifndef COLVARS_VERSION -#define COLVARS_VERSION "2016-08-05" +#define COLVARS_VERSION "2016-08-10" #endif #ifndef COLVARS_DEBUG @@ -23,19 +23,16 @@ /// shared between all object instances) to be accessed from other /// objects. -// Error codes are the negative of powers-of-two -// as a result, error codes should NOT be bitwise-ORed but only -// accessed through set_error_bit() and get_error_bit() #define COLVARS_OK 0 -#define COLVARS_ERROR -1 -#define COLVARS_NOT_IMPLEMENTED (-1*(1<<1)) -#define INPUT_ERROR (-1*(1<<2)) // out of bounds or inconsistent input -#define BUG_ERROR (-1*(1<<3)) // Inconsistent state indicating bug -#define FILE_ERROR (-1*(1<<4)) -#define MEMORY_ERROR (-1*(1<<5)) -#define FATAL_ERROR (-1*(1<<6)) // Should be set, or not, together with other bits -#define DELETE_COLVARS (-1*(1<<7)) // Instruct the caller to delete cvm -#define COLVARS_NO_SUCH_FRAME (-1*(1<<8)) // Cannot load the requested frame +#define COLVARS_ERROR 1 +#define COLVARS_NOT_IMPLEMENTED (1<<1) +#define INPUT_ERROR (1<<2) // out of bounds or inconsistent input +#define BUG_ERROR (1<<3) // Inconsistent state indicating bug +#define FILE_ERROR (1<<4) +#define MEMORY_ERROR (1<<5) +#define FATAL_ERROR (1<<6) // Should be set, or not, together with other bits +#define DELETE_COLVARS (1<<7) // Instruct the caller to delete cvm +#define COLVARS_NO_SUCH_FRAME (1<<8) // Cannot load the requested frame #include #include @@ -118,12 +115,10 @@ protected: public: - static void set_error_bit(int code); + static void set_error_bits(int code); static bool get_error_bit(int code); - static void combine_errors(int &target, int const code); - static inline int get_error() { return errorCode; diff --git a/lib/colvars/colvarparse.cpp b/lib/colvars/colvarparse.cpp index f6e904c83a..da39f78356 100644 --- a/lib/colvars/colvarparse.cpp +++ b/lib/colvars/colvarparse.cpp @@ -354,6 +354,21 @@ bool colvarparse::get_keyval(std::string const &conf, } +bool colvarparse::get_keyval(std::string const &conf, + char const *key, + cvm::deps::feature_state *value, + bool const &def_value, + Parse_Mode const parse_mode) +{ + bool feature_flag = def_value; + bool const b_found = get_keyval(conf, key, feature_flag, def_value, parse_mode); + if (feature_flag) { + value->object()->enable(value->feature_id()); + } + return b_found; +} + + // multiple-value keyword parsers bool colvarparse::get_keyval(std::string const &conf, @@ -548,6 +563,10 @@ bool colvarparse::key_lookup(std::string const &conf, std::string &data, size_t &save_pos) { + if (cvm::debug()) { + cvm::log("Looking for the keyword \""+std::string(key_in)+"\" and its value.\n"); + } + // add this keyword to the register (in its camelCase version) add_keyword(key_in); @@ -568,11 +587,14 @@ bool colvarparse::key_lookup(std::string const &conf, // start from the first occurrence of key size_t pos = conf_lower.find(key, save_pos); - // iterate over all instances until it finds the isolated keyword + // iterate over all instances of the substring until it finds it as isolated keyword while (true) { if (pos == std::string::npos) { // no valid instance of the keyword has been found + if (cvm::debug()) { + cvm::log("Keyword \""+std::string(key_in)+"\" not found.\n"); + } return false; } @@ -625,25 +647,46 @@ bool colvarparse::key_lookup(std::string const &conf, 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; 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) { + size_t brace = line.find('{', data_begin); // look for an opening brace + size_t brace_last = brace; - size_t brace_count = 1; - size_t brace = line.find('{', data_begin); // start from the first opening brace + if (brace != std::string::npos) { + + // find the matching closing brace + + if (cvm::debug()) { + cvm::log("Multi-line value, config is now \""+line+"\".\n"); + } + + int brace_count = 1; while (brace_count > 0) { - // find the matching closing brace - brace = line.find_first_of("{}", brace+1); - while (brace == std::string::npos) { + brace = line.find_first_of("{}", brace_last+1); + // find all braces within this line + while (brace < std::string::npos) { + brace_last = brace; + if (line[brace] == '{') brace_count++; + if (line[brace] == '}') brace_count--; + if (brace_count == 0) { + data_end = brace+1; + break; + } + brace = line.find_first_of("{}", brace+1); + } + + if (brace_count == 0) { + data_end = brace+1; + break; + } + + if (brace == std::string::npos) { + // add a new line if (line_end >= conf.size()) { cvm::error("Parse error: reached the end while " @@ -653,7 +696,6 @@ bool colvarparse::key_lookup(std::string const &conf, 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); @@ -663,36 +705,37 @@ bool colvarparse::key_lookup(std::string const &conf, line_end = nl; line.append(conf, line_begin, (line_end-line_begin)); - brace = line.find_first_of("{}", old_end); + if (cvm::debug()) { + cvm::log("Added a new line, config is now \""+line+"\".\n"); + } } - if (line[brace] == '{') brace_count++; - if (line[brace] == '}') brace_count--; + if (brace_count < 0) { + cvm::error("Error: found closing brace without opening brace.\n", INPUT_ERROR); + } } - // set data_begin after the opening brace - data_begin = line.find_first_of('{', data_begin) + 1; + cvm::log("Value so far = "+line.substr(data_begin, (data_end-data_begin))+".\n"); + + // strip the leading and trailing braces + data_begin = line.find_first_of('{') + 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_absolute = line_end; - if (data_end > line.size()) - data_end = line.size(); + data_end = line.find_last_of('}', line.size()) - 1; + data_end = line.find_last_not_of(white_space, + data_end) + 1; } data.append(line, data_begin, (data_end-data_begin)); + if (cvm::debug()) { + cvm::log("Keyword value = \""+data+"\".\n"); + } + if (data.size() && save_delimiters) { 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"; } } diff --git a/lib/colvars/colvarparse.h b/lib/colvars/colvarparse.h index 9bce5412ed..c091cbc15d 100644 --- a/lib/colvars/colvarparse.h +++ b/lib/colvars/colvarparse.h @@ -8,6 +8,7 @@ #include "colvarmodule.h" #include "colvarvalue.h" +#include "colvardeps.h" /// \file colvarparse.h Parsing functions for collective variables @@ -180,6 +181,11 @@ public: bool &value, bool const &def_value = false, Parse_Mode const parse_mode = parse_normal); + bool get_keyval(std::string const &conf, + char const *key, + cvm::deps::feature_state *value, + bool const &def_value = false, + Parse_Mode const parse_mode = parse_normal); bool get_keyval(std::string const &conf, char const *key, diff --git a/lib/colvars/colvarproxy.h b/lib/colvars/colvarproxy.h index 0d29a7297d..4bba189bb7 100644 --- a/lib/colvars/colvarproxy.h +++ b/lib/colvars/colvarproxy.h @@ -69,12 +69,12 @@ public: virtual cvm::real rand_gaussian(void) = 0; /// \brief Get the current frame number - // Negative return values indicate error - virtual int frame() { return COLVARS_NOT_IMPLEMENTED; } + // Returns error code + virtual int get_frame(long int&) { return COLVARS_NOT_IMPLEMENTED; } - /// \brief Set the current frame number - // return frame number on success, COLVARS_NO_SUCH_FRAME otherwise - virtual int frame(int) { return COLVARS_NOT_IMPLEMENTED; } + /// \brief Set the current frame number (as well as colvarmodule::it) + // Returns error code + virtual int set_frame(long int) { return COLVARS_NOT_IMPLEMENTED; } /// \brief Prefix to be used for input files (restarts, not /// configuration) diff --git a/lib/colvars/colvarscript.cpp b/lib/colvars/colvarscript.cpp index 091162fc18..374359ccef 100644 --- a/lib/colvars/colvarscript.cpp +++ b/lib/colvars/colvarscript.cpp @@ -55,14 +55,14 @@ int colvarscript::run(int argc, char const *argv[]) { if (cmd == "delete") { // Note: the delete bit may be ignored by some backends // it is mostly useful in VMD - colvars->set_error_bit(DELETE_COLVARS); + colvars->set_error_bits(DELETE_COLVARS); return COLVARS_OK; } if (cmd == "update") { - cvm::combine_errors(error_code, proxy->update_input()); - cvm::combine_errors(error_code, colvars->calc()); - cvm::combine_errors(error_code, proxy->update_output()); + error_code |= proxy->update_input(); + error_code |= colvars->calc(); + error_code |= proxy->update_output(); if (error_code) { result += "Error updating the colvars module.\n"; } @@ -142,8 +142,8 @@ int colvarscript::run(int argc, char const *argv[]) { } proxy->output_prefix_str = argv[2]; int error = 0; - cvm::combine_errors(error, colvars->setup_output()); - cvm::combine_errors(error, colvars->write_output_files()); + error |= colvars->setup_output(); + error |= colvars->write_output_files(); return error ? COLVARSCRIPT_ERROR : COLVARS_OK; } @@ -163,8 +163,9 @@ int colvarscript::run(int argc, char const *argv[]) { if (cmd == "frame") { if (argc == 2) { - int f = proxy->frame(); - if (f >= 0) { + long int f; + int error = proxy->get_frame(f); + if (error == COLVARS_OK) { result = cvm::to_str(f); return COLVARS_OK; } else { @@ -173,10 +174,9 @@ int colvarscript::run(int argc, char const *argv[]) { } } 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); + // returns nonzero, to let scripts detect available frames + int error = proxy->set_frame(strtol(argv[2], NULL, 10)); + result = cvm::to_str(error == COLVARS_OK ? 0 : -1); return COLVARS_OK; } else { result = "Wrong arguments to command \"frame\"\n" + help_string(); @@ -414,7 +414,8 @@ Input and output:\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) { + long int tmp; + if (proxy->get_frame(tmp) != COLVARS_NOT_IMPLEMENTED) { buf += "\ frame -- return current frame number\n\ frame -- set frame number\n";