version 1.6 | version 1.7 |
---|
| |
| |
#include "colvardeps.h" | #include "colvardeps.h" |
| |
| colvardeps::colvardeps() |
| : time_step_factor (1) {} |
| |
colvardeps::~colvardeps() { | colvardeps::~colvardeps() { |
size_t i; | size_t i; |
| |
| // Protest if we are deleting an object while a parent object may still depend on it |
| // Another possible strategy is to have the child unlist itself from the parent's children |
| if (parents.size()) { |
| cvm::log("Warning: destroying \"" + description + "\" before its parents objects:"); |
| for (i=0; i<parents.size(); i++) { |
| cvm::log(parents[i]->description); |
| } |
| } |
| |
// Do not delete features if it's static | // Do not delete features if it's static |
// for (i=0; i<features.size(); i++) { | // for (i=0; i<features.size(); i++) { |
// if (features[i] != NULL) delete features[i]; | // if (features[i] != NULL) delete features[i]; |
// } | // } |
| |
remove_all_children(); | remove_all_children(); |
| } |
| |
// Protest if we are deleting an object while a parent object may still depend on it | |
// Another possible strategy is to have the child unlist itself from the parent's children | void colvardeps::free_children_deps() { |
if (parents.size()) { | // Dereference children requirements of all enabled features |
cvm::log("Warning: destroying " + description + " before its parents objects:"); | // Useful when object is destroyed or set inactive |
for (i=0; i<parents.size(); i++) { | // CAUTION: when setting the parent object inactive, disable "active" first |
cvm::log(parents[i]->description); | // then call this, to avoid double-dereferencing the deps of "active" |
| |
| // Cannot be in the base class destructor because it needs the derived class features() |
| size_t i,j,fid; |
| |
| if (cvm::debug()) cvm::log("DEPS: freeing children deps for " + description); |
| |
| for (fid = 0; fid < feature_states.size(); fid++) { |
| if (is_enabled(fid)) { |
| for (i=0; i<features()[fid]->requires_children.size(); i++) { |
| int g = features()[fid]->requires_children[i]; |
| for (j=0; j<children.size(); j++) { |
| cvm::increase_depth(); |
| if (cvm::debug()) cvm::log("DEPS: dereferencing children's " |
| + children[j]->features()[g]->description); |
| children[j]->decr_ref_count(g); |
| cvm::decrease_depth(); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| // re-enable children features (and increase ref count accordingly) |
| // So free_children_deps() can be called whenever an object becomes inactive |
| void colvardeps::restore_children_deps() { |
| size_t i,j,fid; |
| for (fid = 0; fid < feature_states.size(); fid++) { |
| if (is_enabled(fid)) { |
| for (i=0; i<features()[fid]->requires_children.size(); i++) { |
| int g = features()[fid]->requires_children[i]; |
| for (j=0; j<children.size(); j++) { |
| cvm::increase_depth(); |
| if (cvm::debug()) cvm::log("DEPS: re-enabling children's " |
| + children[j]->features()[g]->description); |
| children[j]->enable(g, false, false); |
| cvm::decrease_depth(); |
| } |
| } |
} | } |
} | } |
} | } |
| |
| |
| |
void colvardeps::set_enabled(int feature_id, bool truefalse) { | void colvardeps::set_enabled(int feature_id, bool truefalse) { |
// if (!is_static(feature_id)) { | |
// cvm::error("Cannot set feature " + features()[feature_id]->description + " statically in " + description + ".\n"); | |
// return; | |
// } | |
if (truefalse) { | if (truefalse) { |
// Resolve dependencies too | |
enable(feature_id); | enable(feature_id); |
} else { | } else { |
feature_states[feature_id].enabled = false; | disable(feature_id); |
} | } |
} | } |
| |
| |
colvarparse::Parse_Mode const parse_mode) | colvarparse::Parse_Mode const parse_mode) |
{ | { |
if (!is_user(feature_id)) { | if (!is_user(feature_id)) { |
cvm::error("Cannot set feature " + features()[feature_id]->description + " from user input in " + description + ".\n"); | cvm::error("Cannot set feature \"" + features()[feature_id]->description + "\" from user input in \"" + description + "\".\n"); |
return false; | return false; |
} | } |
bool value; | bool value; |
| |
| |
if (cvm::debug()) { | if (cvm::debug()) { |
cvm::log("DEPS: " + description + | cvm::log("DEPS: " + description + |
(dry_run ? " testing " : " requiring ") + | (dry_run ? " testing " : " enabling ") + |
"\"" + f->description +"\""); | "\"" + f->description +"\""); |
} | } |
| |
if (fs->enabled) { | if (fs->enabled) { |
// Do not try to solve deps if already enabled | if (!(dry_run || toplevel)) { |
| // This is a dependency |
| // Prevent disabling this feature as long |
| // as requirement is enabled |
| fs->ref_count++; |
| if (cvm::debug()) |
| cvm::log("DEPS: bumping ref_count to " + cvm::to_str(fs->ref_count)); |
| } |
| // Do not try to further resolve deps |
return COLVARS_OK; | return COLVARS_OK; |
} | } |
| |
| std::string feature_type_descr = is_static(feature_id) ? "Static" : |
| (is_dynamic(feature_id) ? "Dynamic" : "User-controlled"); |
| |
if (!fs->available) { | if (!fs->available) { |
if (!dry_run) { | if (!dry_run) { |
if (toplevel) { | if (toplevel) { |
cvm::error("Error: Feature unavailable: \"" + f->description + "\" in " + description + "."); | cvm::error("Error: " + feature_type_descr + " feature unavailable: \"" |
| + f->description + "\" in " + description + "."); |
} else { | } else { |
cvm::log("Feature unavailable: \"" + f->description + "\" in " + description); | cvm::log(feature_type_descr + " feature unavailable: \"" |
| + f->description + "\" in " + description + "."); |
} | } |
} | } |
return COLVARS_ERROR; | return COLVARS_ERROR; |
| |
| |
if (!toplevel && !is_dynamic(feature_id)) { | if (!toplevel && !is_dynamic(feature_id)) { |
if (!dry_run) { | if (!dry_run) { |
cvm::log("Non-dynamic feature : \"" + f->description | cvm::log(feature_type_descr + " feature \"" + f->description |
+ "\" in " + description + " may not be enabled as a dependency.\n"); | + "\" may not be enabled as a dependency in " + description + ".\n"); |
} | } |
return COLVARS_ERROR; | return COLVARS_ERROR; |
} | } |
| |
// 1) enforce exclusions | // 1) enforce exclusions |
| // reminder: exclusions must be mutual for this to work |
for (i=0; i<f->requires_exclude.size(); i++) { | for (i=0; i<f->requires_exclude.size(); i++) { |
feature *g = features()[f->requires_exclude[i]]; | feature *g = features()[f->requires_exclude[i]]; |
if (cvm::debug()) | if (cvm::debug()) |
cvm::log(f->description + " requires exclude " + g->description); | cvm::log(f->description + " requires exclude " + g->description); |
if (is_enabled(f->requires_exclude[i])) { | if (is_enabled(f->requires_exclude[i])) { |
if (!dry_run) { | if (!dry_run) { |
cvm::log("Features \"" + f->description + "\" is incompatible with \"" | cvm::log("Feature \"" + f->description + "\" is incompatible with \"" |
+ g->description + "\" in " + description); | + g->description + "\" in " + description + "."); |
if (toplevel) { | if (toplevel) { |
cvm::error("Error: Failed dependency in " + description + "."); | cvm::error("Error: Failed dependency in " + description + "."); |
} | } |
| |
res = enable(g, true, false); // see if available | res = enable(g, true, false); // see if available |
if (res == COLVARS_OK) { | if (res == COLVARS_OK) { |
ok = true; | ok = true; |
if (!dry_run) enable(g, false, false); // Require again, for real | if (!dry_run) { |
| enable(g, false, false); // Require again, for real |
| fs->alternate_refs.push_back(g); // We remember we enabled this |
| // so we can free it if this feature gets disabled |
| } |
break; | break; |
} | } |
} | } |
| |
} | } |
| |
// 4) solve deps in children | // 4) solve deps in children |
| // if the object is inactive, we solve but do not enable: will be enabled |
| // when the object becomes active |
for (i=0; i<f->requires_children.size(); i++) { | for (i=0; i<f->requires_children.size(); i++) { |
int g = f->requires_children[i]; | int g = f->requires_children[i]; |
for (j=0; j<children.size(); j++) { | for (j=0; j<children.size(); j++) { |
cvm::increase_depth(); | cvm::increase_depth(); |
res = children[j]->enable(g, dry_run, false); | res = children[j]->enable(g, dry_run || !is_enabled(), false); |
cvm::decrease_depth(); | cvm::decrease_depth(); |
if (res != COLVARS_OK) { | if (res != COLVARS_OK) { |
if (!dry_run) { | if (!dry_run) { |
| |
return res; | return res; |
} | } |
} | } |
// If we've just touched the features of child objects, refresh them | } |
if (!dry_run && f->requires_children.size() != 0) { | |
| // Actually enable feature only once everything checks out |
| if (!dry_run) { |
| fs->enabled = true; |
| // This should be the only reference |
| if (!toplevel) fs->ref_count = 1; |
| if (feature_id == 0) { |
| // Waking up this object, enable all deps in children |
| restore_children_deps(); |
| } |
| do_feature_side_effects(feature_id); |
| if (cvm::debug()) |
| cvm::log("DEPS: feature \"" + f->description + "\" in " |
| + description + " enabled, ref_count = 1."); |
| } |
| return COLVARS_OK; |
| } |
| |
| |
| int colvardeps::disable(int feature_id) { |
| size_t i, j; |
| feature *f = features()[feature_id]; |
| feature_state *fs = &feature_states[feature_id]; |
| |
| if (cvm::debug()) cvm::log("DEPS: disabling feature \"" |
| + f->description + "\" in " + description); |
| |
| if (fs->enabled == false) { |
| return COLVARS_OK; |
| } |
| |
| if (fs->ref_count > 1) { |
| cvm::error("Error: cannot disable feature \"" + f->description |
| + "\" in " + description + " because of " + cvm::to_str(fs->ref_count-1) |
| + " remaining references.\n" ); |
| return COLVARS_ERROR; |
| } |
| |
| // internal deps (self) |
| for (i=0; i<f->requires_self.size(); i++) { |
| if (cvm::debug()) cvm::log("DEPS: dereferencing self " |
| + features()[f->requires_self[i]]->description); |
| decr_ref_count(f->requires_self[i]); |
| } |
| |
| // alternates |
| for (i=0; i<fs->alternate_refs.size(); i++) { |
| if (cvm::debug()) cvm::log("DEPS: dereferencing alt " |
| + features()[fs->alternate_refs[i]]->description); |
| decr_ref_count(fs->alternate_refs[i]); |
| } |
| // Forget these, now that they are dereferenced |
| fs->alternate_refs.clear(); |
| |
| // deps in children |
| // except if the object is inactive, then children dependencies |
| // have already been dereferenced by this function |
| // (or never referenced if feature was enabled while the object |
| // was inactive) |
| if (is_enabled()) { |
| for (i=0; i<f->requires_children.size(); i++) { |
| int g = f->requires_children[i]; |
for (j=0; j<children.size(); j++) { | for (j=0; j<children.size(); j++) { |
children[j]->refresh_deps(); | cvm::increase_depth(); |
| if (cvm::debug()) cvm::log("DEPS: dereferencing children's " |
| + children[j]->features()[g]->description); |
| children[j]->decr_ref_count(g); |
| cvm::decrease_depth(); |
} | } |
} | } |
} | } |
| |
// Actually enable feature only once everything checks out | fs->enabled = false; |
if (!dry_run) fs->enabled = true; | fs->ref_count = 0; |
| if (feature_id == 0) { |
| // Putting this object to sleep |
| free_children_deps(); |
| } |
return COLVARS_OK; | return COLVARS_OK; |
} | } |
| |
| int colvardeps::decr_ref_count(int feature_id) { |
| int &rc = feature_states[feature_id].ref_count; |
| feature *f = features()[feature_id]; |
| |
| if (cvm::debug()) |
| cvm::log("DEPS: decreasing reference count of \"" + f->description |
| + "\" in " + description + ".\n"); |
| |
| if (rc <= 0) { |
| cvm::error("Error: cannot decrease reference count of feature \"" + f->description + "\" in " + description + ", which is " + cvm::to_str(rc) + ".\n"); |
| return COLVARS_ERROR; |
| } |
| |
| rc--; |
| if (rc == 0 && f->is_dynamic()) { |
| // we can auto-disable this feature |
| if (cvm::debug()) |
| cvm::log("DEPS will now auto-disable dynamic feature \"" + f->description |
| + "\" in " + description + ".\n"); |
| disable(feature_id); |
| } |
| return COLVARS_OK; |
| } |
| |
// disable() { | |
// | |
// // we need refs to parents to walk up the deps tree! | |
// // or refresh | |
// } | |
void colvardeps::init_feature(int feature_id, const char *description, feature_type type) { | void colvardeps::init_feature(int feature_id, const char *description, feature_type type) { |
features()[feature_id]->description = description; | features()[feature_id]->description = description; |
features()[feature_id]->type = type; | features()[feature_id]->type = type; |
| |
init_feature(f_cvb_active, "active", f_type_dynamic); | init_feature(f_cvb_active, "active", f_type_dynamic); |
f_req_children(f_cvb_active, f_cv_active); | f_req_children(f_cvb_active, f_cv_active); |
| |
| init_feature(f_cvb_awake, "awake", f_type_static); |
| f_req_self(f_cvb_awake, f_cvb_active); |
| |
init_feature(f_cvb_apply_force, "apply force", f_type_user); | init_feature(f_cvb_apply_force, "apply force", f_type_user); |
f_req_children(f_cvb_apply_force, f_cv_gradient); | f_req_children(f_cvb_apply_force, f_cv_gradient); |
| |
| |
// Colvars must be either a linear combination, or scalar (and polynomial) or scripted | // Colvars must be either a linear combination, or scalar (and polynomial) or scripted |
f_req_alt3(f_cv_active, f_cv_scalar, f_cv_linear, f_cv_scripted); | f_req_alt3(f_cv_active, f_cv_scalar, f_cv_linear, f_cv_scripted); |
| |
| init_feature(f_cv_awake, "awake", f_type_static); |
| f_req_self(f_cv_awake, f_cv_active); |
| |
init_feature(f_cv_gradient, "gradient", f_type_dynamic); | init_feature(f_cv_gradient, "gradient", f_type_dynamic); |
f_req_children(f_cv_gradient, f_cvc_gradient); | f_req_children(f_cv_gradient, f_cvc_gradient); |
| |
init_feature(f_cv_collect_gradient, "collect gradient", f_type_dynamic); | init_feature(f_cv_collect_gradient, "collect gradient", f_type_dynamic); |
f_req_self(f_cv_collect_gradient, f_cv_gradient); | f_req_self(f_cv_collect_gradient, f_cv_gradient); |
f_req_self(f_cv_collect_gradient, f_cv_scalar); | f_req_self(f_cv_collect_gradient, f_cv_scalar); |
| // The following exlusion could be lifted by implementing the feature |
| f_req_exclude(f_cv_collect_gradient, f_cv_scripted); |
| |
init_feature(f_cv_fdiff_velocity, "fdiff_velocity", f_type_dynamic); | init_feature(f_cv_fdiff_velocity, "fdiff_velocity", f_type_dynamic); |
| |
| |
init_feature(f_cv_scalar, "scalar", f_type_static); | init_feature(f_cv_scalar, "scalar", f_type_static); |
init_feature(f_cv_linear, "linear", f_type_static); | init_feature(f_cv_linear, "linear", f_type_static); |
init_feature(f_cv_homogeneous, "homogeneous", f_type_static); | init_feature(f_cv_homogeneous, "homogeneous", f_type_static); |
| |
| // because total forces are obtained from the previous time step, |
| // we cannot (currently) have colvar values and total forces for the same timestep |
| init_feature(f_cv_multiple_ts, "multiple timestep colvar"); |
| f_req_exclude(f_cv_multiple_ts, f_cv_total_force_calc); |
} | } |
| |
// Initialize feature_states for each instance | // Initialize feature_states for each instance |
| |
init_feature(f_ag_center, "translational fit", f_type_static); | init_feature(f_ag_center, "translational fit", f_type_static); |
init_feature(f_ag_rotate, "rotational fit", f_type_static); | init_feature(f_ag_rotate, "rotational fit", f_type_static); |
init_feature(f_ag_fitting_group, "reference positions group", f_type_static); | init_feature(f_ag_fitting_group, "reference positions group", f_type_static); |
init_feature(f_ag_fit_gradient_group, "fit gradient for main group", f_type_static); | init_feature(f_ag_fit_gradients, "fit gradients", f_type_user); |
init_feature(f_ag_fit_gradient_ref, "fit gradient for reference group", f_type_static); | |
init_feature(f_ag_atom_forces, "atomic forces", f_type_dynamic); | init_feature(f_ag_atom_forces, "atomic forces", f_type_dynamic); |
| |
// parallel calculation implies that we have at least a scalable center of mass, | // parallel calculation implies that we have at least a scalable center of mass, |
| |
feature_states[f_ag_scalable_com].available = false; | feature_states[f_ag_scalable_com].available = false; |
// TODO make f_ag_scalable depend on f_ag_scalable_com (or something else) | // TODO make f_ag_scalable depend on f_ag_scalable_com (or something else) |
feature_states[f_ag_scalable].available = true; | feature_states[f_ag_scalable].available = true; |
| feature_states[f_ag_fit_gradients].available = true; |
} | } |
| |
| |
void colvardeps::print_state() { | void colvardeps::print_state() { |
size_t i; | size_t i; |
cvm::log("Enabled features of " + description); | cvm::log("Enabled features of \"" + description + "\" (with reference count)"); |
for (i = 0; i < feature_states.size(); i++) { | for (i = 0; i < feature_states.size(); i++) { |
if (feature_states[i].enabled) | if (is_enabled(i)) |
cvm::log("- " + features()[i]->description); | cvm::log("- " + features()[i]->description + " (" |
| + cvm::to_str(feature_states[i].ref_count) + ")"); |
} | } |
for (i=0; i<children.size(); i++) { | for (i=0; i<children.size(); i++) { |
cvm::log("* child " + cvm::to_str(i+1)); | cvm::log("* child " + cvm::to_str(i+1)); |