From 0a6b87fb35251e7fa5258e21e7311a28ed610646 Mon Sep 17 00:00:00 2001 From: HanatoK Date: Tue, 12 Mar 2024 11:55:17 -0500 Subject: [PATCH] Make some CVs (PCVs and NN-based CVs) more robust. Return the error code earlier to prevent crashes in interactive programs. --- src/colvarcomp_apath.cpp | 4 ++++ src/colvarcomp_combination.cpp | 11 ++++++----- src/colvarcomp_gpath.cpp | 13 +++++++++++-- src/colvarcomp_neuralnetwork.cpp | 12 ++++++------ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/colvarcomp_apath.cpp b/src/colvarcomp_apath.cpp index af1b338d6..9e8256957 100644 --- a/src/colvarcomp_apath.cpp +++ b/src/colvarcomp_apath.cpp @@ -144,6 +144,7 @@ colvar::aspath::aspath() int colvar::aspath::init(std::string const &conf) { int error_code = CartesianBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); cvm::real p_lambda; get_keyval(conf, "lambda", p_lambda, -1.0); @@ -198,6 +199,7 @@ colvar::azpath::azpath() int colvar::azpath::init(std::string const &conf) { int error_code = CartesianBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); x.type(colvarvalue::type_scalar); cvm::real p_lambda; @@ -252,6 +254,7 @@ colvar::aspathCV::aspathCV() int colvar::aspathCV::init(std::string const &conf) { int error_code = CVBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); std::vector p_weights(cv.size(), 1.0); get_keyval(conf, "weights", p_weights, std::vector(cv.size(), 1.0)); @@ -356,6 +359,7 @@ colvar::azpathCV::azpathCV() int colvar::azpathCV::init(std::string const &conf) { int error_code = CVBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); std::vector p_weights(cv.size(), 1.0); get_keyval(conf, "weights", p_weights, std::vector(cv.size(), 1.0)); diff --git a/src/colvarcomp_combination.cpp b/src/colvarcomp_combination.cpp index 2bbc5bfa6..01c7ffc32 100644 --- a/src/colvarcomp_combination.cpp +++ b/src/colvarcomp_combination.cpp @@ -19,6 +19,7 @@ colvar::linearCombination::linearCombination() int colvar::linearCombination::init(std::string const &conf) { int error_code = cvc::init(conf); + if (error_code != COLVARS_OK) return error_code; // Lookup all available sub-cvcs for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) { @@ -40,8 +41,7 @@ int colvar::linearCombination::init(std::string const &conf) } // Show useful error messages and prevent crashes if no sub CVC is found if (cv.size() == 0) { - error_code |= - cvm::error("Error: the CV " + name + " expects one or more nesting components.\n", + return cvm::error("Error: the CV " + name + " expects one or more nesting components.\n", COLVARS_INPUT_ERROR); } else { x.type(cv[0]->value()); @@ -170,6 +170,7 @@ colvar::customColvar::customColvar() int colvar::customColvar::init(std::string const &conf) { int error_code = linearCombination::init(conf); + if (error_code != COLVARS_OK) return error_code; // code swipe from colvar::init_custom_function std::string expr_in, expr; @@ -191,7 +192,7 @@ int colvar::customColvar::init(std::string const &conf) pexpr = Lepton::Parser::parse(expr); pexprs.push_back(pexpr); } catch (...) { - cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR); + return cvm::error("Error parsing expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR); } try { value_evaluators.push_back(new Lepton::CompiledExpression(pexpr.createCompiledExpression())); @@ -209,7 +210,7 @@ int colvar::customColvar::init(std::string const &conf) } } } catch (...) { - cvm::error("Error compiling expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR); + return cvm::error("Error compiling expression \"" + expr + "\".\n", COLVARS_INPUT_ERROR); } } while (key_lookup(conf, "customFunction", &expr_in, &pos)); // Now define derivative with respect to each scalar sub-component @@ -234,7 +235,7 @@ int colvar::customColvar::init(std::string const &conf) } } if (value_evaluators.size() == 0) { - cvm::error("Error: no custom function defined.\n", COLVARS_INPUT_ERROR); + return cvm::error("Error: no custom function defined.\n", COLVARS_INPUT_ERROR); } if (value_evaluators.size() != 1) { x.type(colvarvalue::type_vector); diff --git a/src/colvarcomp_gpath.cpp b/src/colvarcomp_gpath.cpp index 4d05da74a..46d6b8e5a 100644 --- a/src/colvarcomp_gpath.cpp +++ b/src/colvarcomp_gpath.cpp @@ -31,6 +31,7 @@ colvar::CartesianBasedPath::CartesianBasedPath() int colvar::CartesianBasedPath::init(std::string const &conf) { int error_code = cvc::init(conf); + if (error_code != COLVARS_OK) return error_code; // Parse selected atoms atoms = parse_group(conf, "atoms"); @@ -182,6 +183,7 @@ colvar::gspath::gspath() int colvar::gspath::init(std::string const &conf) { int error_code = CartesianBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); if (use_second_closest_frame == true) { @@ -336,6 +338,7 @@ colvar::gzpath::gzpath() int colvar::gzpath::init(std::string const &conf) { int error_code = CartesianBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; get_keyval(conf, "useSecondClosestFrame", use_second_closest_frame, true); if (use_second_closest_frame == true) { @@ -481,6 +484,7 @@ colvar::CVBasedPath::CVBasedPath() int colvar::CVBasedPath::init(std::string const &conf) { int error_code = cvc::init(conf); + if (error_code != COLVARS_OK) return error_code; // Lookup all available sub-cvcs for (auto it_cv_map = colvar::get_global_cvc_map().begin(); it_cv_map != colvar::get_global_cvc_map().end(); ++it_cv_map) { @@ -534,6 +538,7 @@ int colvar::CVBasedPath::init(std::string const &conf) } } else { error_code = cvm::error("Error: incorrect format of path file.\n", COLVARS_INPUT_ERROR); + return error_code; } } if (!fields.empty()) { @@ -546,11 +551,13 @@ int colvar::CVBasedPath::init(std::string const &conf) error_code = cvm::error( "Error: there is only 1 or 0 reference frame, which doesn't constitute a path.\n", COLVARS_INPUT_ERROR); + return error_code; } if (cv.size() == 0) { error_code = cvm::error("Error: the CV " + name + " expects one or more nesting components.\n", COLVARS_INPUT_ERROR); + return error_code; } use_explicit_gradients = true; @@ -672,6 +679,7 @@ colvar::gspathCV::gspathCV() int colvar::gspathCV::init(std::string const &conf) { int error_code = CVBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); // Initialize variables for future calculation @@ -688,7 +696,7 @@ int colvar::gspathCV::init(std::string const &conf) cvm::log(std::string("Geometric path s(σ) will use the neighbouring frame to compute s_(m+1)\n")); } if (total_reference_frames < 2) { - error_code |= cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspathCV requires at least 2 frames.\n", COLVARS_INPUT_ERROR); + return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gspathCV requires at least 2 frames.\n", COLVARS_INPUT_ERROR); } GeometricPathCV::GeometricPathBase::initialize(cv.size(), ref_cv[0], total_reference_frames, use_second_closest_frame, use_third_closest_frame); return error_code; @@ -801,6 +809,7 @@ colvar::gzpathCV::gzpathCV() int colvar::gzpathCV::init(std::string const &conf) { int error_code = CVBasedPath::init(conf); + if (error_code != COLVARS_OK) return error_code; cvm::log(std::string("Total number of frames: ") + cvm::to_str(total_reference_frames) + std::string("\n")); // Initialize variables for future calculation @@ -824,7 +833,7 @@ int colvar::gzpathCV::init(std::string const &conf) { cvm::log(std::string("Geometric path z(σ) will use the square of distance from current frame to path compute z\n")); } if (total_reference_frames < 2) { - error_code |= cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + + return cvm::error("Error: you have specified " + cvm::to_str(total_reference_frames) + " reference frames, but gzpathCV requires at least 2 frames.\n", COLVARS_INPUT_ERROR); } diff --git a/src/colvarcomp_neuralnetwork.cpp b/src/colvarcomp_neuralnetwork.cpp index 621911be6..2d2f89d5f 100644 --- a/src/colvarcomp_neuralnetwork.cpp +++ b/src/colvarcomp_neuralnetwork.cpp @@ -25,6 +25,7 @@ colvar::neuralNetwork::neuralNetwork() int colvar::neuralNetwork::init(std::string const &conf) { int error_code = linearCombination::init(conf); + if (error_code != COLVARS_OK) return error_code; // the output of neural network consists of multiple values // read "output_component" key to determine it get_keyval(conf, "output_component", m_output_index); @@ -73,8 +74,7 @@ int colvar::neuralNetwork::init(std::string const &conf) std::string function_name; get_keyval(conf, lookup_key.c_str(), function_name, std::string("")); if (activation_function_map.find(function_name) == activation_function_map.end()) { - error_code |= - cvm::error("Unknown activation function name: \"" + function_name + "\".\n", + return cvm::error("Unknown activation function name: \"" + function_name + "\".\n", COLVARS_INPUT_ERROR); } activation_functions.push_back(std::make_pair(false, function_name)); @@ -94,7 +94,7 @@ int colvar::neuralNetwork::init(std::string const &conf) } // expect the three numbers are equal if ((num_layers_weight != num_layers_bias) || (num_layers_bias != num_activation_functions)) { - error_code |= cvm::error( + return cvm::error( "Error: the numbers of weights, biases and activation functions do not match.\n", COLVARS_INPUT_ERROR); } @@ -110,7 +110,7 @@ int colvar::neuralNetwork::init(std::string const &conf) try { d = denseLayer(weight_files[i_layer], bias_files[i_layer], activation_functions[i_layer].second); } catch (std::exception &ex) { - error_code |= cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + + return cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR); } @@ -122,7 +122,7 @@ int colvar::neuralNetwork::init(std::string const &conf) try { d = denseLayer(weight_files[i_layer], bias_files[i_layer], f, df); } catch (std::exception &ex) { - error_code |= cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + + return cvm::error("Error on initializing layer " + cvm::to_str(i_layer) + " (" + ex.what() + ")\n", COLVARS_INPUT_ERROR); } @@ -142,7 +142,7 @@ int colvar::neuralNetwork::init(std::string const &conf) } } } else { - error_code |= cvm::error("Error: error on adding a new dense layer.\n", COLVARS_INPUT_ERROR); + return cvm::error("Error: error on adding a new dense layer.\n", COLVARS_INPUT_ERROR); } } nn->input().resize(cv.size());