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 Sat Apr 20 02:42:24 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002