00001
00002
00003
00004
00005
00006
00007
00008
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
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
00034
00035
00036
00037
00038
00039 remove_all_children();
00040 }
00041
00042
00043 void colvardeps::free_children_deps() {
00044
00045
00046
00047
00048
00049
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
00072
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
00119 set_enabled(feature_id, value);
00120
00121 return found;
00122 }
00123
00124
00125 int colvardeps::enable(int feature_id,
00126 bool dry_run ,
00127 bool toplevel )
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
00144
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
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
00181
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
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
00215 for (i=0; i<f->requires_alt.size(); i++) {
00216
00217
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);
00224 if (res == COLVARS_OK) {
00225 ok = true;
00226 if (!dry_run) {
00227 enable(g, false, false);
00228 fs->alternate_refs.push_back(g);
00229
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);
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
00256
00257
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
00277 if (!dry_run) {
00278 fs->enabled = true;
00279
00280 if (!toplevel) fs->ref_count = 1;
00281 if (feature_id == 0) {
00282
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
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
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
00327 fs->alternate_refs.clear();
00328
00329
00330
00331
00332
00333
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
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
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
00390 void colvardeps::require_feature_self(int f, int g) {
00391 features()[f]->requires_self.push_back(g);
00392 }
00393
00394
00395
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
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
00456
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 }