Main Page Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

colvardeps.C

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 
00003 // This file is part of the Collective Variables module (Colvars).
00004 // The original version of Colvars and its updates are located at:
00005 // https://github.com/Colvars/colvars
00006 // Please update all Colvars source files before making any changes.
00007 // If you wish to distribute your changes, please submit them to the
00008 // Colvars repository at GitHub.
00009 
00010 
00011 #include "colvarmodule.h"
00012 #include "colvarproxy.h"
00013 #include "colvardeps.h"
00014 
00015 
00016 colvardeps::colvardeps()
00017 {
00018 time_step_factor = 1;
00019 }
00020 
00021 
00022 colvardeps::~colvardeps() {
00023 size_t i;
00024 
00025 // Protest if we are deleting an object while a parent object may still depend on it
00026 if (parents.size()) {
00027 cvm::log("Warning: destroying \"" + description + "\" before its parents objects:");
00028 for (i=0; i<parents.size(); i++) {
00029 cvm::log(parents[i]->description + "\n");
00030 }
00031 }
00032 
00033 // Do not delete features if it's a static object
00034 // may change in the future though
00035 // for (i=0; i<features.size(); i++) {
00036 // if (features[i] != NULL) delete features[i];
00037 // }
00038 
00039 remove_all_children();
00040 }
00041 
00042 
00043 void colvardeps::free_children_deps() {
00044 // Dereference children requirements of all enabled features
00045 // Useful when object is destroyed or set inactive
00046 // CAUTION: when setting the parent object inactive, disable "active" first
00047 // then call this, to avoid double-dereferencing the deps of "active"
00048 
00049 // Cannot be in the base class destructor because it needs the derived class features()
00050 size_t i,j,fid;
00051 
00052 if (cvm::debug()) cvm::log("DEPS: freeing children deps for " + description + "\n");
00053 
00054 cvm::increase_depth();
00055 for (fid = 0; fid < feature_states.size(); fid++) {
00056 if (is_enabled(fid)) {
00057 for (i=0; i<features()[fid]->requires_children.size(); i++) {
00058 int g = features()[fid]->requires_children[i];
00059 for (j=0; j<children.size(); j++) {
00060 if (cvm::debug()) cvm::log("DEPS: dereferencing children's "
00061 + children[j]->features()[g]->description + "\n");
00062 children[j]->decr_ref_count(g);
00063 }
00064 }
00065 }
00066 }
00067 cvm::decrease_depth();
00068 }
00069 
00070 
00071 // re-enable children features (and increase ref count accordingly)
00072 // So free_children_deps() can be called whenever an object becomes inactive
00073 void colvardeps::restore_children_deps() {
00074 size_t i,j,fid;
00075 
00076 cvm::increase_depth();
00077 for (fid = 0; fid < feature_states.size(); fid++) {
00078 if (is_enabled(fid)) {
00079 for (i=0; i<features()[fid]->requires_children.size(); i++) {
00080 int g = features()[fid]->requires_children[i];
00081 for (j=0; j<children.size(); j++) {
00082 if (cvm::debug()) cvm::log("DEPS: re-enabling children's "
00083 + children[j]->features()[g]->description + "\n");
00084 children[j]->enable(g, false, false);
00085 }
00086 }
00087 }
00088 }
00089 cvm::decrease_depth();
00090 }
00091 
00092 
00093 void colvardeps::provide(int feature_id, bool truefalse) {
00094 feature_states[feature_id].available = truefalse;
00095 }
00096 
00097 
00098 void colvardeps::set_enabled(int feature_id, bool truefalse) {
00099 if (truefalse) {
00100 enable(feature_id);
00101 } else {
00102 disable(feature_id);
00103 }
00104 }
00105 
00106 
00107 bool colvardeps::get_keyval_feature(colvarparse *cvp,
00108 std::string const &conf, char const *key,
00109 int feature_id, bool const &def_value,
00110 colvarparse::Parse_Mode const parse_mode)
00111 {
00112 if (!is_user(feature_id)) {
00113 cvm::error("Cannot set feature \"" + features()[feature_id]->description + "\" from user input in \"" + description + "\".\n");
00114 return false;
00115 }
00116 bool value;
00117 bool const found = cvp->get_keyval(conf, key, value, def_value, parse_mode);
00118 // If the default value is on, this function should be able to disable the feature!
00119 set_enabled(feature_id, value);
00120 
00121 return found;
00122 }
00123 
00124 
00125 int colvardeps::enable(int feature_id,
00126 bool dry_run /* default: false */,
00127 bool toplevel /* default: true */)
00128 {
00129 int res;
00130 size_t i, j;
00131 bool ok;
00132 feature *f = features()[feature_id];
00133 feature_state *fs = &feature_states[feature_id];
00134 
00135 if (cvm::debug()) {
00136 cvm::log("DEPS: " + description +
00137 (dry_run ? " testing " : " enabling ") +
00138 "\"" + f->description +"\"\n");
00139 }
00140 
00141 if (fs->enabled) {
00142 if (!(dry_run || toplevel)) {
00143 // This is a dependency: prevent disabling this feature as long
00144 // as requirement is enabled
00145 fs->ref_count++;
00146 if (cvm::debug())
00147 cvm::log("DEPS: bumping ref_count to " + cvm::to_str(fs->ref_count) + "\n");
00148 }
00149 // Do not try to further resolve deps
00150 return COLVARS_OK;
00151 }
00152 
00153 std::string feature_type_descr = is_static(feature_id) ? "Static" :
00154 (is_dynamic(feature_id) ? "Dynamic" : "User-controlled");
00155 
00156 if (!fs->available) {
00157 if (!dry_run) {
00158 if (toplevel) {
00159 cvm::error("Error: " + feature_type_descr + " feature unavailable: \""
00160 + f->description + "\" in " + description + ".\n");
00161 } else {
00162 cvm::log(feature_type_descr + " feature unavailable: \""
00163 + f->description + "\" in " + description + ".\n");
00164 }
00165 }
00166 return COLVARS_ERROR;
00167 }
00168 
00169 if (!toplevel && !is_dynamic(feature_id)) {
00170 if (!dry_run) {
00171 cvm::log(feature_type_descr + " feature \"" + f->description
00172 + "\" cannot be enabled automatically in " + description + ".\n");
00173 if (is_user(feature_id)) {
00174 cvm::log("Try setting it manually.\n");
00175 }
00176 }
00177 return COLVARS_ERROR;
00178 }
00179 
00180 // 1) enforce exclusions
00181 // reminder: exclusions must be mutual for this to work
00182 for (i=0; i<f->requires_exclude.size(); i++) {
00183 feature *g = features()[f->requires_exclude[i]];
00184 if (cvm::debug())
00185 cvm::log(f->description + " requires exclude " + g->description + "\n");
00186 if (is_enabled(f->requires_exclude[i])) {
00187 if (!dry_run) {
00188 cvm::log("Feature \"" + f->description + "\" is incompatible with \""
00189 + g->description + "\" in " + description + ".\n");
00190 if (toplevel) {
00191 cvm::error("Error: Failed dependency in " + description + ".\n");
00192 }
00193 }
00194 return COLVARS_ERROR;
00195 }
00196 }
00197 
00198 // 2) solve internal deps (self)
00199 for (i=0; i<f->requires_self.size(); i++) {
00200 if (cvm::debug())
00201 cvm::log(f->description + " requires self " + features()[f->requires_self[i]]->description + "\n");
00202 res = enable(f->requires_self[i], dry_run, false);
00203 if (res != COLVARS_OK) {
00204 if (!dry_run) {
00205 cvm::log("...required by \"" + f->description + "\" in " + description + "\n");
00206 if (toplevel) {
00207 cvm::error("Error: Failed dependency in " + description + ".\n");
00208 }
00209 }
00210 return res;
00211 }
00212 }
00213 
00214 // 3) solve internal alternate deps
00215 for (i=0; i<f->requires_alt.size(); i++) {
00216 
00217 // test if one is available; if yes, enable and exit w/ success
00218 ok = false;
00219 for (j=0; j<f->requires_alt[i].size(); j++) {
00220 int g = f->requires_alt[i][j];
00221 if (cvm::debug())
00222 cvm::log(f->description + " requires alt " + features()[g]->description + "\n");
00223 res = enable(g, true, false); // see if available
00224 if (res == COLVARS_OK) {
00225 ok = true;
00226 if (!dry_run) {
00227 enable(g, false, false); // Require again, for real
00228 fs->alternate_refs.push_back(g); // We remember we enabled this
00229 // so we can free it if this feature gets disabled
00230 }
00231 break;
00232 }
00233 }
00234 if (!ok) {
00235 if (!dry_run) {
00236 cvm::log("\"" + f->description + "\" in " + description
00237 + " requires one of the following features, none of which can be enabled:\n");
00238 cvm::log("-----------------------------------------\n");
00239 cvm::increase_depth();
00240 for (j=0; j<f->requires_alt[i].size(); j++) {
00241 int g = f->requires_alt[i][j];
00242 cvm::log(cvm::to_str(j+1) + ". " + features()[g]->description + "\n");
00243 enable(g, false, false); // Just for printing error output
00244 }
00245 cvm::decrease_depth();
00246 cvm::log("-----------------------------------------\n");
00247 if (toplevel) {
00248 cvm::error("Error: Failed dependency in " + description + ".\n");
00249 }
00250 }
00251 return COLVARS_ERROR;
00252 }
00253 }
00254 
00255 // 4) solve deps in children
00256 // if the object is inactive, we solve but do not enable: will be enabled
00257 // when the object becomes active
00258 cvm::increase_depth();
00259 for (i=0; i<f->requires_children.size(); i++) {
00260 int g = f->requires_children[i];
00261 for (j=0; j<children.size(); j++) {
00262 res = children[j]->enable(g, dry_run || !is_enabled(), false);
00263 if (res != COLVARS_OK) {
00264 if (!dry_run) {
00265 cvm::log("...required by \"" + f->description + "\" in " + description + "\n");
00266 if (toplevel) {
00267 cvm::error("Error: Failed dependency in " + description + ".\n");
00268 }
00269 }
00270 return res;
00271 }
00272 }
00273 }
00274 cvm::decrease_depth();
00275 
00276 // Actually enable feature only once everything checks out
00277 if (!dry_run) {
00278 fs->enabled = true;
00279 // This should be the only reference
00280 if (!toplevel) fs->ref_count = 1;
00281 if (feature_id == 0) {
00282 // Waking up this object, enable all deps in children
00283 restore_children_deps();
00284 }
00285 do_feature_side_effects(feature_id);
00286 if (cvm::debug())
00287 cvm::log("DEPS: feature \"" + f->description + "\" in "
00288 + description + " enabled, ref_count = 1." + "\n");
00289 }
00290 return COLVARS_OK;
00291 }
00292 
00293 
00294 int colvardeps::disable(int feature_id) {
00295 size_t i, j;
00296 feature *f = features()[feature_id];
00297 feature_state *fs = &feature_states[feature_id];
00298 
00299 if (cvm::debug()) cvm::log("DEPS: disabling feature \""
00300 + f->description + "\" in " + description + "\n");
00301 
00302 if (fs->enabled == false) {
00303 return COLVARS_OK;
00304 }
00305 
00306 if (fs->ref_count > 1) {
00307 cvm::error("Error: cannot disable feature \"" + f->description
00308 + "\" in " + description + " because of " + cvm::to_str(fs->ref_count-1)
00309 + " remaining references.\n" );
00310 return COLVARS_ERROR;
00311 }
00312 
00313 // internal deps (self)
00314 for (i=0; i<f->requires_self.size(); i++) {
00315 if (cvm::debug()) cvm::log("DEPS: dereferencing self "
00316 + features()[f->requires_self[i]]->description + "\n");
00317 decr_ref_count(f->requires_self[i]);
00318 }
00319 
00320 // alternates
00321 for (i=0; i<fs->alternate_refs.size(); i++) {
00322 if (cvm::debug()) cvm::log("DEPS: dereferencing alt "
00323 + features()[fs->alternate_refs[i]]->description + "\n");
00324 decr_ref_count(fs->alternate_refs[i]);
00325 }
00326 // Forget these, now that they are dereferenced
00327 fs->alternate_refs.clear();
00328 
00329 // deps in children
00330 // except if the object is inactive, then children dependencies
00331 // have already been dereferenced by this function
00332 // (or never referenced if feature was enabled while the object
00333 // was inactive)
00334 if (is_enabled()) {
00335 cvm::increase_depth();
00336 for (i=0; i<f->requires_children.size(); i++) {
00337 int g = f->requires_children[i];
00338 for (j=0; j<children.size(); j++) {
00339 if (cvm::debug()) cvm::log("DEPS: dereferencing children's "
00340 + children[j]->features()[g]->description + "\n");
00341 children[j]->decr_ref_count(g);
00342 }
00343 }
00344 cvm::decrease_depth();
00345 }
00346 
00347 fs->enabled = false;
00348 fs->ref_count = 0;
00349 if (feature_id == 0) {
00350 // Putting this object to sleep
00351 free_children_deps();
00352 }
00353 return COLVARS_OK;
00354 }
00355 
00356 
00357 int colvardeps::decr_ref_count(int feature_id) {
00358 int &rc = feature_states[feature_id].ref_count;
00359 feature *f = features()[feature_id];
00360 
00361 if (cvm::debug())
00362 cvm::log("DEPS: decreasing reference count of \"" + f->description
00363 + "\" in " + description + ".\n");
00364 
00365 if (rc <= 0) {
00366 cvm::error("Error: cannot decrease reference count of feature \"" + f->description
00367 + "\" in " + description + ", which is " + cvm::to_str(rc) + ".\n");
00368 return COLVARS_ERROR;
00369 }
00370 
00371 rc--;
00372 if (rc == 0 && f->is_dynamic()) {
00373 // we can auto-disable this feature
00374 if (cvm::debug())
00375 cvm::log("DEPS will now auto-disable dynamic feature \"" + f->description
00376 + "\" in " + description + ".\n");
00377 disable(feature_id);
00378 }
00379 return COLVARS_OK;
00380 }
00381 
00382 
00383 void colvardeps::init_feature(int feature_id, const char *description_in, feature_type type) {
00384 modify_features()[feature_id]->description = description_in;
00385 modify_features()[feature_id]->type = type;
00386 }
00387 
00388 
00389 // Shorthand functions for describing dependencies
00390 void colvardeps::require_feature_self(int f, int g) {
00391 features()[f]->requires_self.push_back(g);
00392 }
00393 
00394 
00395 // Ensure that exclusions are symmetric
00396 void colvardeps::exclude_feature_self(int f, int g) {
00397 features()[f]->requires_exclude.push_back(g);
00398 features()[g]->requires_exclude.push_back(f);
00399 }
00400 
00401 
00402 void colvardeps::require_feature_children(int f, int g) {
00403 features()[f]->requires_children.push_back(g);
00404 }
00405 
00406 
00407 void colvardeps::require_feature_alt(int f, int g, int h) {
00408 features()[f]->requires_alt.push_back(std::vector<int>(2));
00409 features()[f]->requires_alt.back()[0] = g;
00410 features()[f]->requires_alt.back()[1] = h;
00411 }
00412 
00413 
00414 void colvardeps::require_feature_alt(int f, int g, int h, int i) {
00415 features()[f]->requires_alt.push_back(std::vector<int>(3));
00416 features()[f]->requires_alt.back()[0] = g;
00417 features()[f]->requires_alt.back()[1] = h;
00418 features()[f]->requires_alt.back()[2] = i;
00419 }
00420 
00421 
00422 void colvardeps::require_feature_alt(int f, int g, int h, int i, int j) {
00423 features()[f]->requires_alt.push_back(std::vector<int>(4));
00424 features()[f]->requires_alt.back()[0] = g;
00425 features()[f]->requires_alt.back()[1] = h;
00426 features()[f]->requires_alt.back()[2] = i;
00427 features()[f]->requires_alt.back()[3] = j;
00428 }
00429 
00430 
00431 void colvardeps::print_state() {
00432 size_t i;
00433 cvm::log("Features of \"" + description + "\" (refcount)\n");
00434 for (i = 0; i < feature_states.size(); i++) {
00435 std::string onoff = is_enabled(i) ? "ON " : " ";
00436 // Only display refcount if non-zero for less clutter
00437 std::string refcount = feature_states[i].ref_count != 0 ?
00438 " (" + cvm::to_str(feature_states[i].ref_count) + ") " : "";
00439 cvm::log("- " + onoff + features()[i]->description + refcount + "\n");
00440 }
00441 cvm::increase_depth();
00442 for (i=0; i<children.size(); i++) {
00443 cvm::log("* child " + cvm::to_str(i+1));
00444 children[i]->print_state();
00445 }
00446 cvm::decrease_depth();
00447 }
00448 
00449 
00450 void colvardeps::add_child(colvardeps *child) {
00451 
00452 children.push_back(child);
00453 child->parents.push_back(this);
00454 
00455 // Solve dependencies of already enabled parent features
00456 // in the new child
00457 
00458 size_t i, fid;
00459 cvm::increase_depth();
00460 for (fid = 0; fid < feature_states.size(); fid++) {
00461 if (is_enabled(fid)) {
00462 for (i=0; i<features()[fid]->requires_children.size(); i++) {
00463 int g = features()[fid]->requires_children[i];
00464 if (cvm::debug()) cvm::log("DEPS: re-enabling children's "
00465 + child->features()[g]->description + "\n");
00466 child->enable(g, false, false);
00467 }
00468 }
00469 }
00470 cvm::decrease_depth();
00471 }
00472 
00473 
00474 void colvardeps::remove_child(colvardeps *child) {
00475 int i;
00476 bool found = false;
00477 
00478 for (i = children.size()-1; i>=0; --i) {
00479 if (children[i] == child) {
00480 children.erase(children.begin() + i);
00481 found = true;
00482 break;
00483 }
00484 }
00485 if (!found) {
00486 cvm::error("Trying to remove missing child reference from " + description + "\n");
00487 }
00488 found = false;
00489 for (i = child->parents.size()-1; i>=0; --i) {
00490 if (child->parents[i] == this) {
00491 child->parents.erase(child->parents.begin() + i);
00492 found = true;
00493 break;
00494 }
00495 }
00496 if (!found) {
00497 cvm::error("Trying to remove missing parent reference from " + child->description + "\n");
00498 }
00499 }
00500 
00501 
00502 void colvardeps::remove_all_children() {
00503 size_t i;
00504 int j;
00505 bool found;
00506 
00507 for (i = 0; i < children.size(); ++i) {
00508 found = false;
00509 for (j = children[i]->parents.size()-1; j>=0; --j) {
00510 if (children[i]->parents[j] == this) {
00511 children[i]->parents.erase(children[i]->parents.begin() + j);
00512 found = true;
00513 break;
00514 }
00515 }
00516 if (!found) {
00517 cvm::error("Trying to remove missing parent reference from " + children[i]->description + "\n");
00518 }
00519 }
00520 children.clear();
00521 }

Generated on Wed Nov 19 02:45:57 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /