diff --git a/modules/io/pymod/wrap_io.cc b/modules/io/pymod/wrap_io.cc index 8704a4657d5a7f152f96d339164976fe5bbeb0ce..4b64e61891f710fc4f4aecf4fa9d4eb44add1942 100644 --- a/modules/io/pymod/wrap_io.cc +++ b/modules/io/pymod/wrap_io.cc @@ -68,6 +68,11 @@ BOOST_PYTHON_FUNCTION_OVERLOADS(save_entity_handle_ov, BOOST_PYTHON_FUNCTION_OVERLOADS(save_entity_view_ov, save_ent_view, 2, 3) +ost::mol::alg::StereoChemicalProps (*read_props_a)(String filename, bool check) = &ReadStereoChemicalPropsFile; +ost::mol::alg::StereoChemicalProps (*read_props_b)(bool check) = &ReadStereoChemicalPropsFile; + + +Real (*lddt_c)(const mol::EntityView&, const mol::EntityView& , Real, Real, const String&)=&mol::alg::LocalDistDiffTest; } void export_pdb_io(); @@ -121,14 +126,11 @@ BOOST_PYTHON_MODULE(_ost_io) def("LoadMAE", &LoadMAE); def("LoadPQR", &LoadPQR); - class_<io::StereoChemicalParamsReader>("StereoChemicalParamsReader", - init<String>(arg("filename"))) - .def(init<>()) - .def("Read", &io::StereoChemicalParamsReader::Read, (arg("check")=false)) - .def_readwrite("filename", &io::StereoChemicalParamsReader::filename) - .def_readwrite("bond_table", &io::StereoChemicalParamsReader::bond_table) - .def_readwrite("angle_table", &io::StereoChemicalParamsReader::angle_table) - .def_readwrite("nonbonded_table", &io::StereoChemicalParamsReader::nonbonded_table); + def("ReadStereoChemicalPropsFile", read_props_a, + (arg("filename"), arg("check")=true)); + def("ReadStereoChemicalPropsFile", read_props_b, + (arg("check")=true)); + def("GetStereoChemicalPropsFile", &GetStereoChemicalPropsFile); export_pdb_io(); export_mmcif_io(); diff --git a/modules/io/src/mol/stereochemical_params_reader.cc b/modules/io/src/mol/stereochemical_params_reader.cc index f0317a3ea19ae8dd78b675a4c08576555e5e659a..0201caf573168a860ae10190cef51ec526238ed2 100644 --- a/modules/io/src/mol/stereochemical_params_reader.cc +++ b/modules/io/src/mol/stereochemical_params_reader.cc @@ -18,47 +18,50 @@ //------------------------------------------------------------------------------ #include <boost/filesystem/fstream.hpp> #include <ost/platform.hh> -#include <ost/mol/alg/filter_clashes.hh> #include <ost/io/stereochemical_params_reader.hh> -namespace { - std::vector<String> ReadStereoChemicalFile(const String& filename){ - boost::filesystem::path loc(filename); - boost::filesystem::ifstream infile(loc); - if (!infile) { - std::stringstream serr; - serr << "Could not find " << filename; - throw ost::Error(serr.str()); - } - std::vector<String> stereo_chemical_props; - String line; - while (std::getline(infile, line)) - { - std::stringstream line_stream(line); - stereo_chemical_props.push_back(line); - } - - return stereo_chemical_props; - } -} - namespace ost { namespace io { -StereoChemicalParamsReader::StereoChemicalParamsReader() { - filename = ost::GetSharedDataPath() + "/stereo_chemical_props.txt"; -} +ost::mol::alg::StereoChemicalProps ReadStereoChemicalPropsFile(String filename, bool check){ + boost::filesystem::path loc(filename); + boost::filesystem::ifstream infile(loc); + if (!infile) { + std::stringstream serr; + serr << "Could not find parameter file '" << filename << "'"; + throw ost::Error(serr.str()); + } + std::vector<String> stereo_chemical_props; + String line; + while (std::getline(infile, line)) + { + std::stringstream line_stream(line); + stereo_chemical_props.push_back(line); + } -StereoChemicalParamsReader::StereoChemicalParamsReader(const String& init_filename): filename(init_filename) {} + ost::mol::alg::StereoChemicalParams bond_table; + ost::mol::alg::StereoChemicalParams angle_table; + ost::mol::alg::ClashingDistances nonbonded_table; -void StereoChemicalParamsReader::Read(bool check) { - std::vector<String> stereo_chemical_props = ReadStereoChemicalFile(filename); - // Bonds bond_table = ost::mol::alg::FillStereoChemicalParams("Bond", stereo_chemical_props, check); // Angles angle_table = ost::mol::alg::FillStereoChemicalParams("Angle", stereo_chemical_props, check); // Not bonded nonbonded_table = ost::mol::alg::FillClashingDistances(stereo_chemical_props, check); + + return ost::mol::alg::StereoChemicalProps(bond_table, angle_table, nonbonded_table); +} + +ost::mol::alg::StereoChemicalProps ReadStereoChemicalPropsFile(bool check) { + String filename = GetStereoChemicalPropsFile(); + return ReadStereoChemicalPropsFile(filename, check); } + +String GetStereoChemicalPropsFile() { + String filename; + filename = ost::GetSharedDataPath() + "/stereo_chemical_props.txt"; + return filename; +} + }} // ns diff --git a/modules/io/src/mol/stereochemical_params_reader.hh b/modules/io/src/mol/stereochemical_params_reader.hh index f8990f55268de150d6f17a28160f53e695781bfa..a5d33acce7888bdcd88b74ec0aecd38a120eb9d6 100644 --- a/modules/io/src/mol/stereochemical_params_reader.hh +++ b/modules/io/src/mol/stereochemical_params_reader.hh @@ -20,20 +20,13 @@ #define OST_IO_STEREOCHEMICAL_PARAMS_READER_H #include <ost/io/module_config.hh> -#include <ost/mol/alg/filter_clashes.hh> +#include <ost/mol/alg/local_dist_diff_test.hh> namespace ost { namespace io { -struct StereoChemicalParamsReader { - String filename; - ost::mol::alg::StereoChemicalParams bond_table; - ost::mol::alg::StereoChemicalParams angle_table; - ost::mol::alg::ClashingDistances nonbonded_table; - - StereoChemicalParamsReader(); - StereoChemicalParamsReader(const String& filename); - void Read(bool check=false); -}; +ost::mol::alg::StereoChemicalProps ReadStereoChemicalPropsFile(String filename, bool check=false); +ost::mol::alg::StereoChemicalProps ReadStereoChemicalPropsFile(bool check=false); +String GetStereoChemicalPropsFile(); }} // ns diff --git a/modules/mol/alg/pymod/wrap_mol_alg.cc b/modules/mol/alg/pymod/wrap_mol_alg.cc index ac7471758bd2ab4a88230d9d7a2aa7a20324563f..d4a7c208c0d518bb08141a4b2f5cd34c788c802b 100644 --- a/modules/mol/alg/pymod/wrap_mol_alg.cc +++ b/modules/mol/alg/pymod/wrap_mol_alg.cc @@ -20,6 +20,7 @@ #include <boost/python.hpp> #include <boost/python/raw_function.hpp> #include <boost/python/suite/indexing/map_indexing_suite.hpp> +#include <ost/log.hh> #include <ost/config.hh> #include <ost/mol/alg/local_dist_diff_test.hh> #include <ost/mol/alg/distance_test_common.hh> @@ -151,12 +152,6 @@ object lDDTSettingsInitWrapper(tuple args, dict kwargs){ kwargs["sel"].del(); } - String parameter_file_path = ""; - if(kwargs.contains("parameter_file_path")){ - parameter_file_path = extract<String>(kwargs["parameter_file_path"]); - kwargs["parameter_file_path"].del(); - } - bool structural_checks = true; if(kwargs.contains("structural_checks")){ structural_checks = extract<bool>(kwargs["structural_checks"]); @@ -192,7 +187,7 @@ object lDDTSettingsInitWrapper(tuple args, dict kwargs){ if(len(kwargs) > 0){ std::stringstream ss; - ss << "Invalid keywords observed when setting up MolckSettings! "; + ss << "Invalid keywords observed when setting up lDDTSettings! "; ss << "Or did you pass the same keyword twice? "; ss << "Valid keywords are: bond_tolerance, angle_tolerance, radius, "; ss << "sequence_separation, sel, parameter_file_path, structural_checks, "; @@ -205,13 +200,65 @@ object lDDTSettingsInitWrapper(tuple args, dict kwargs){ radius, sequence_separation, sel, - parameter_file_path, structural_checks, consistency_checks, cutoffs, label); } +object lDDTScorerInitWrapper(tuple args, dict kwargs){ + + object self = args[0]; + args = tuple(args.slice(1, len(args))); + + std::vector<ost::mol::EntityHandle> reference_list_vector; + if(kwargs.contains("references")){ + list reference_list = boost::python::extract<list>(kwargs["references"]); + int reference_list_length = boost::python::extract<int>(reference_list.attr("__len__")()); + for (int i=0; i<reference_list_length; i++) { + reference_list_vector.push_back(boost::python::extract<ost::mol::EntityHandle>(reference_list[i])); + } + kwargs["references"].del(); + } else { + throw std::invalid_argument("'references' argument is required"); + } + + ost::mol::EntityHandle model; + if(kwargs.contains("model")){ + model = boost::python::extract<ost::mol::EntityHandle>(kwargs["model"]); + kwargs["model"].del(); + } else { + throw std::invalid_argument("'model' argument is required"); + } + + ost::mol::alg::lDDTSettings settings; + if(kwargs.contains("settings")){ + settings = extract<ost::mol::alg::lDDTSettings>(kwargs["settings"]); + kwargs["settings"].del(); + } else { + throw std::invalid_argument("'settings' argument is required"); + } + + ost::mol::alg::StereoChemicalProps stereochemical_params; + if(kwargs.contains("stereochemical_params")){ + stereochemical_params = extract<ost::mol::alg::StereoChemicalProps>(kwargs["stereochemical_params"]); + kwargs["stereochemical_params"].del(); + } + + if(len(kwargs) > 0){ + std::stringstream ss; + ss << "Invalid keywords observed when setting up lDDTScorer! "; + ss << "Or did you pass the same keyword twice? "; + ss << "Valid keywords are: settings and stereochemical_params!"; + throw std::invalid_argument(ss.str()); + } + + return self.attr("__init__")(reference_list_vector, + model, + settings, + stereochemical_params); +} + void clean_lddt_references_wrapper(const list& reference_list) { @@ -225,7 +272,10 @@ void clean_lddt_references_wrapper(const list& reference_list) return ost::mol::alg::CleanlDDTReferences(reference_list_vector); } -ost::mol::alg::GlobalRDMap prepare_lddt_global_rdmap_wrapper(const list& reference_list, mol::alg::lDDTSettings settings) +ost::mol::alg::GlobalRDMap prepare_lddt_global_rdmap_wrapper(const list& reference_list, + list& cutoff_list, + int sequence_separation, + Real max_dist) { int reference_list_length = boost::python::extract<int>(reference_list.attr("__len__")()); std::vector<ost::mol::EntityView> reference_list_vector(reference_list_length); @@ -233,14 +283,22 @@ ost::mol::alg::GlobalRDMap prepare_lddt_global_rdmap_wrapper(const list& referen for (int i=0; i<reference_list_length; i++) { reference_list_vector[i] = boost::python::extract<ost::mol::EntityView>(reference_list[i]); } + + int cutoff_list_length = boost::python::extract<int>(cutoff_list.attr("__len__")()); + std::vector<Real> cutoff_list_vector(cutoff_list_length); + + for (int i=0; i<cutoff_list_length; i++) { + cutoff_list_vector[i] = boost::python::extract<Real>(cutoff_list[i]); + } - return mol::alg::PreparelDDTGlobalRDMap(reference_list_vector, settings); + return mol::alg::PreparelDDTGlobalRDMap(reference_list_vector, cutoff_list_vector, sequence_separation, max_dist); } list get_lddt_per_residue_stats_wrapper(mol::EntityHandle& model, ost::mol::alg::GlobalRDMap& distance_list, - ost::mol::alg::lDDTSettings& settings) { - std::vector<mol::alg::lDDTLocalScore> scores = GetlDDTPerResidueStats(model, distance_list, settings); + bool structural_checks, + String label) { + std::vector<mol::alg::lDDTLocalScore> scores = GetlDDTPerResidueStats(model, distance_list, structural_checks, label); list local_scores_list; for (std::vector<mol::alg::lDDTLocalScore>::const_iterator sit = scores.begin(); sit != scores.end(); ++sit) { local_scores_list.append(*sit); @@ -248,7 +306,16 @@ list get_lddt_per_residue_stats_wrapper(mol::EntityHandle& model, return local_scores_list; } -void print_lddt_per_residue_stats_wrapper(list& scores, mol::alg::lDDTSettings settings){ +list get_local_scores_wrapper(mol::alg::lDDTScorer& scorer) { + std::vector<mol::alg::lDDTLocalScore> scores = scorer.GetLocalScores(); + list local_scores_list; + for (std::vector<mol::alg::lDDTLocalScore>::const_iterator sit = scores.begin(); sit != scores.end(); ++sit) { + local_scores_list.append(*sit); + } + return local_scores_list; +} + +void print_lddt_per_residue_stats_wrapper(list& scores, bool structural_checks, int cutoffs_size){ int scores_length = boost::python::extract<int>(scores.attr("__len__")()); std::vector<mol::alg::lDDTLocalScore> scores_vector(scores_length); @@ -256,7 +323,7 @@ void print_lddt_per_residue_stats_wrapper(list& scores, mol::alg::lDDTSettings s scores_vector[i] = boost::python::extract<mol::alg::lDDTLocalScore>(scores[i]); } - return mol::alg::PrintlDDTPerResidueStats(scores_vector, settings); + return mol::alg::PrintlDDTPerResidueStats(scores_vector, structural_checks, cutoffs_size); } } @@ -326,9 +393,8 @@ BOOST_PYTHON_MODULE(_ost_mol_alg) class_<mol::alg::lDDTSettings>("lDDTSettings", no_init) .def("__init__", raw_function(lDDTSettingsInitWrapper)) - .def(init<Real, Real, Real, int, String, String, bool, bool, std::vector<Real>&, String>()) + .def(init<Real, Real, Real, int, String, bool, bool, std::vector<Real>&, String>()) .def("ToString", &mol::alg::lDDTSettings::ToString) - .def("SetStereoChemicalParamsPath", &mol::alg::lDDTSettings::SetStereoChemicalParamsPath) .def("PrintParameters", &mol::alg::lDDTSettings::PrintParameters) .def("__repr__", &mol::alg::lDDTSettings::ToString) .def("__str__", &mol::alg::lDDTSettings::ToString) @@ -337,7 +403,6 @@ BOOST_PYTHON_MODULE(_ost_mol_alg) .def_readwrite("radius", &mol::alg::lDDTSettings::radius) .def_readwrite("sequence_separation", &mol::alg::lDDTSettings::sequence_separation) .def_readwrite("sel", &mol::alg::lDDTSettings::sel) - .def_readwrite("parameter_file_path", &mol::alg::lDDTSettings::parameter_file_path) .def_readwrite("structural_checks", &mol::alg::lDDTSettings::structural_checks) .def_readwrite("consistency_checks", &mol::alg::lDDTSettings::consistency_checks) .def_readwrite("cutoffs", &mol::alg::lDDTSettings::cutoffs) @@ -346,6 +411,8 @@ BOOST_PYTHON_MODULE(_ost_mol_alg) class_<mol::alg::lDDTLocalScore>("lDDTLocalScore", init<String, String, int, String, String, Real, int, int>()) .def("ToString", &mol::alg::lDDTLocalScore::ToString) .def("GetHeader", &mol::alg::lDDTLocalScore::GetHeader) + .def("__str__", &mol::alg::lDDTLocalScore::Repr) + .def("__repr__", &mol::alg::lDDTLocalScore::Repr) .def_readwrite("cname", &mol::alg::lDDTLocalScore::cname) .def_readwrite("rname", &mol::alg::lDDTLocalScore::rname) .def_readwrite("rnum", &mol::alg::lDDTLocalScore::rnum) @@ -354,6 +421,24 @@ BOOST_PYTHON_MODULE(_ost_mol_alg) .def_readwrite("local_lddt", &mol::alg::lDDTLocalScore::local_lddt) .def_readwrite("conserved_dist", &mol::alg::lDDTLocalScore::conserved_dist) .def_readwrite("total_dist", &mol::alg::lDDTLocalScore::total_dist); + + class_<mol::alg::lDDTScorer>("lDDTScorer", no_init) + .def("__init__", raw_function(lDDTScorerInitWrapper)) + .def(init<std::vector<mol::EntityHandle>&, mol::EntityHandle&, mol::alg::lDDTSettings&, mol::alg::StereoChemicalProps&>()) + .add_property("global_score", &mol::alg::lDDTScorer::GetGlobalScore) + .add_property("conserved_residues", &mol::alg::lDDTScorer::GetNumConservedResidues) + .add_property("total_residues", &mol::alg::lDDTScorer::GetNumTotalResidues) + .def("PrintPerResidueStats", &mol::alg::lDDTScorer::PrintPerResidueStats) + .add_property("local_scores", &get_local_scores_wrapper) + .add_property("is_valid", &mol::alg::lDDTScorer::IsValid); + + class_<mol::alg::StereoChemicalProps>("StereoChemicalProps", + init<mol::alg::StereoChemicalParams&, + mol::alg::StereoChemicalParams&, + mol::alg::ClashingDistances&>()) + .def_readwrite("bond_table", &mol::alg::StereoChemicalProps::bond_table) + .def_readwrite("angle_table", &mol::alg::StereoChemicalProps::angle_table) + .def_readwrite("nonbonded_table", &mol::alg::StereoChemicalProps::nonbonded_table); def("FillClashingDistances",&fill_clashing_distances_wrapper); def("FillStereoChemicalParams",&fill_stereochemical_params_wrapper); @@ -363,17 +448,17 @@ BOOST_PYTHON_MODULE(_ost_mol_alg) def("CleanlDDTReferences", &clean_lddt_references_wrapper); def("PreparelDDTGlobalRDMap", &prepare_lddt_global_rdmap_wrapper, - (arg("reference_list"), arg("settings"))); + (arg("reference_list"), arg("cutoffs"), arg("sequence_separation"), arg("radius"))); def("CheckStructure", &mol::alg::CheckStructure, (arg("ent"), arg("bond_table"), arg("angle_table"), arg("nonbonded_table"), arg("bond_tolerance"), arg("angle_tolerance"))); def("GetlDDTPerResidueStats", &get_lddt_per_residue_stats_wrapper, - (arg("model"), arg("distance_list"), arg("settings"))); + (arg("model"), arg("distance_list"), arg("structural_checks"), arg("label"))); def("PrintlDDTPerResidueStats", &print_lddt_per_residue_stats_wrapper, - (arg("scores"), arg("settings"))); + (arg("scores"), arg("structural_checks"), arg("cutoff_list_length"))); class_<mol::alg::PDBize>("PDBize", diff --git a/modules/mol/alg/src/lddt.cc b/modules/mol/alg/src/lddt.cc index 60156b86b4515c773994cd3031252915525c07fe..e9117757b0696ca982561ca8f82dd5aad328f491 100644 --- a/modules/mol/alg/src/lddt.cc +++ b/modules/mol/alg/src/lddt.cc @@ -157,6 +157,7 @@ int main (int argc, char **argv) // sets some default values for parameters String version = OST_VERSION_STRING; lDDTSettings settings; + String parameter_file_path; settings.structural_checks=false; // creates the required loading profile IOProfile profile; @@ -224,7 +225,7 @@ int main (int argc, char **argv) } if (vm.count("parameter-file")) { - settings.parameter_file_path=vm["parameter-file"].as<String>(); + parameter_file_path=vm["parameter-file"].as<String>(); } else if (settings.structural_checks==true) { std::cout << "Please specify a stereo-chemical parameter file" << std::endl; exit(-1); @@ -290,7 +291,10 @@ int main (int argc, char **argv) } } CleanlDDTReferences(ref_list); - glob_dist_list = PreparelDDTGlobalRDMap(ref_list, settings); + glob_dist_list = PreparelDDTGlobalRDMap(ref_list, + settings.cutoffs, + settings.sequence_separation, + settings.radius); files.pop_back(); // prints out parameters used in the lddt calculation @@ -326,9 +330,9 @@ int main (int argc, char **argv) std::cout << "File: " << files[i] << std::endl; if (settings.structural_checks) { - StereoChemicalParamsReader stereochemical_params(settings.parameter_file_path); + StereoChemicalProps stereochemical_params; try { - stereochemical_params.Read(true); + stereochemical_params = ost::io::ReadStereoChemicalPropsFile(parameter_file_path, true); } catch (std::exception& e) { std::cout << e.what() << std::endl; exit(-1); @@ -352,8 +356,8 @@ int main (int argc, char **argv) // prints the residue-by-residue statistics std::vector<lDDTLocalScore> local_scores; - local_scores = GetlDDTPerResidueStats(model, glob_dist_list, settings); - PrintlDDTPerResidueStats(local_scores, settings); + local_scores = GetlDDTPerResidueStats(model, glob_dist_list, settings.structural_checks, settings.label); + PrintlDDTPerResidueStats(local_scores, settings.structural_checks, settings.cutoffs.size()); } return 0; } diff --git a/modules/mol/alg/src/local_dist_diff_test.cc b/modules/mol/alg/src/local_dist_diff_test.cc index 9c988d1005c1ca2614a48fbf74e7258a07caf135..d02f41a32e2d89a7ba1c2255b6e4d4c0033557c2 100644 --- a/modules/mol/alg/src/local_dist_diff_test.cc +++ b/modules/mol/alg/src/local_dist_diff_test.cc @@ -7,6 +7,7 @@ #include <boost/concept_check.hpp> #include <boost/filesystem/convenience.hpp> #include <ost/mol/alg/consistency_checks.hh> +#include <ost/io/stereochemical_params_reader.hh> namespace ost { namespace mol { namespace alg { @@ -388,7 +389,19 @@ bool IsStandardResidue(String rn) return true; } return false; -} +} + +StereoChemicalProps::StereoChemicalProps(): + is_valid(false) {} + +StereoChemicalProps::StereoChemicalProps( + ost::mol::alg::StereoChemicalParams& init_bond_table, + ost::mol::alg::StereoChemicalParams& init_angle_table, + ost::mol::alg::ClashingDistances& init_nonbonded_table): + bond_table(init_bond_table), + angle_table(init_angle_table), + nonbonded_table(init_nonbonded_table), + is_valid(true) {} lDDTSettings::lDDTSettings(): bond_tolerance(12.0), angle_tolerance(12.0), @@ -402,7 +415,6 @@ lDDTSettings::lDDTSettings(): bond_tolerance(12.0), cutoffs.push_back(1.0); cutoffs.push_back(2.0); cutoffs.push_back(4.0); - SetStereoChemicalParamsPath(); } lDDTSettings::lDDTSettings(Real init_bond_tolerance, @@ -410,7 +422,6 @@ lDDTSettings::lDDTSettings(Real init_bond_tolerance, Real init_radius, int init_sequence_separation, String init_sel, - String init_parameter_file_path, bool init_structural_checks, bool init_consistency_checks, std::vector<Real>& init_cutoffs, @@ -423,33 +434,7 @@ lDDTSettings::lDDTSettings(Real init_bond_tolerance, structural_checks(init_structural_checks), consistency_checks(init_consistency_checks), cutoffs(init_cutoffs), - label(init_label) { - SetStereoChemicalParamsPath(init_parameter_file_path); -} - -void lDDTSettings::SetStereoChemicalParamsPath(const String& path) { - if (path == ""){ - try { - std::cerr << "Setting default stereochemical parameters file path." << std::endl; - parameter_file_path = ost::GetSharedDataPath() + "/stereo_chemical_props.txt"; - if (! structural_checks) { - std::cerr << "WARNING: Stereochemical parameters file is set but structural checks are disabled" << std::endl; - } - } catch (std::runtime_error& e) { - std::cerr << "WARNING: " << e.what() << std::endl; - std::cerr << "WARNING: Parameter file setting failed - structural check will be disabled" << std::endl; - structural_checks = false; - parameter_file_path = ""; - } - } else if (! boost::filesystem::exists(path)) { - std::cerr << "WARNING: Parameter file does not exist - structural check will be disabled" << std::endl; - structural_checks = false; - parameter_file_path = ""; - } else { - parameter_file_path = path; - structural_checks = true; - } -} + label(init_label) {} std::string lDDTSettings::ToString() { std::ostringstream rep; @@ -464,7 +449,6 @@ std::string lDDTSettings::ToString() { rep << "Cutoffs: " << vector_to_string(cutoffs) << "\n"; if (structural_checks) { - rep << "Parameter filename: " + parameter_file_path + "\n"; rep << "Tolerance in stddevs for bonds: " << bond_tolerance << "\n"; rep << "Tolerance in stddevs for angles: " << angle_tolerance << "\n"; } @@ -517,6 +501,12 @@ String lDDTLocalScore::ToString(bool structural_checks) const { return outstr.str(); } +String lDDTLocalScore::Repr() const { + std::stringstream outstr; + outstr << "<lDDTLocalScore " << cname << "." << rname << "." << rnum << ">"; + return outstr.str(); +} + String lDDTLocalScore::GetHeader(bool structural_checks, int cutoffs_length) { std::stringstream outstr; if (structural_checks) { @@ -527,6 +517,205 @@ String lDDTLocalScore::GetHeader(bool structural_checks, int cutoffs_length) { return outstr.str(); } + +lDDTScorer::lDDTScorer(std::vector<EntityHandle>& init_references, + ost::mol::EntityHandle& init_model, + lDDTSettings& init_settings): + references(init_references), + model(init_model), + settings(init_settings), + _score_calculated(false), + _score_valid(false), + _has_local_scores(false), + _num_con_res(-1), + _num_tot_res(-1), + _global_score(-1.0) + { + model_view = model.GetChainList()[0].Select("peptide=true"); + _PrepareReferences(); + _PrepareGlobalRDMap(); + if (settings.structural_checks) { + if (!stereochemical_params.is_valid) { + throw std::runtime_error( + "Structural checks are ON. Please provide stereochemical_params to enable structural checks."); + } + try { + CheckStructure(model_view, + stereochemical_params.bond_table, + stereochemical_params.angle_table, + stereochemical_params.nonbonded_table, + settings.bond_tolerance, + settings.angle_tolerance); + } catch (std::exception& e) { + std::cout << e.what() << std::endl; + std::stringstream errstr; + errstr << "Structure check failed: " << e.what(); + throw std::runtime_error(errstr.str()); + } + } + } + +lDDTScorer::lDDTScorer(std::vector<EntityHandle>& init_references, + ost::mol::EntityHandle& init_model, + lDDTSettings& init_settings, + StereoChemicalProps& init_stereochemical_params): + references(init_references), + model(init_model), + settings(init_settings), + stereochemical_params(init_stereochemical_params), + _score_calculated(false), + _score_valid(false), + _has_local_scores(false), + _num_con_res(-1), + _num_tot_res(-1), + _global_score(-1.0) { + model_view = model.GetChainList()[0].Select("peptide=true"); + _PrepareReferences(); + _PrepareGlobalRDMap(); + if (settings.structural_checks) { + if (!stereochemical_params.is_valid) { + throw std::runtime_error( + "Please provide stereochemical_params to enable structural_checks."); + } + try { + CheckStructure(model_view, + stereochemical_params.bond_table, + stereochemical_params.angle_table, + stereochemical_params.nonbonded_table, + settings.bond_tolerance, + settings.angle_tolerance); + } catch (std::exception& e) { + std::cout << e.what() << std::endl; + std::stringstream errstr; + errstr << "Structure check failed: " << e.what(); + throw std::runtime_error(errstr.str()); + } + } + } + +Real lDDTScorer::GetGlobalScore(){ + if (!_score_calculated) { + _ComputelDDT(); + } + return _global_score; +} + +int lDDTScorer::GetNumConservedResidues(){ + if (!_score_calculated) { + _ComputelDDT(); + } + return _num_con_res; +} + +int lDDTScorer::GetNumTotalResidues(){ + if (!_score_calculated) { + _ComputelDDT(); + } + return _num_tot_res; +} + +std::vector<lDDTLocalScore> lDDTScorer::GetLocalScores(){ + if (!_has_local_scores) { + _GetLocallDDT(); + } + return _local_scores; +} + +void lDDTScorer::PrintPerResidueStats(){ + if (!_has_local_scores) { + _GetLocallDDT(); + } + PrintlDDTPerResidueStats(_local_scores, + settings.structural_checks, + settings.cutoffs.size()); +} + +void lDDTScorer::_PrepareReferences(){ + for (unsigned int i = 0; i < references.size(); i++) { + if (settings.sel != ""){ + std::cout << "Performing \"" << settings.sel << "\" selection on reference " << references[i].GetName() << std::endl; + try { + references_view.push_back(references[i].Select(settings.sel)); + } catch (const ost::mol::QueryError& e) { + std::stringstream errstr; + errstr << "Provided selection argument failed." << std::endl << e.GetFormattedMessage(); + throw std::runtime_error(errstr.str()); + } + } + else { + references_view.push_back(references[i].CreateFullView()); + } + } + + CleanlDDTReferences(references_view); +} + +void lDDTScorer::_PrepareGlobalRDMap(){ + glob_dist_list = PreparelDDTGlobalRDMap(references_view, + settings.cutoffs, + settings.sequence_separation, + settings.radius); +} + +bool lDDTScorer::IsValid(){ + return _score_valid; +} + +void lDDTScorer::_CheckConsistency(){ + for (std::vector<EntityView>::const_iterator ref_list_it = references_view.begin(); + ref_list_it != references_view.end(); ++ref_list_it) { + bool cons_check = ResidueNamesMatch(model_view, *ref_list_it, settings.consistency_checks); + if (cons_check == false) { + if (settings.consistency_checks == true) { + throw std::runtime_error("Residue names in model and in reference structure(s) are inconsistent."); + } else { + LOG_WARNING("Residue names in model and in reference structure(s) are inconsistent."); + } + } + } +} + +void lDDTScorer::_ComputelDDT(){ + std::pair<int,int> cov = ComputeCoverage(model_view,glob_dist_list); + if (cov.second == -1) { + std::cout << "Coverage: 0 (0 out of 0 residues)" << std::endl; + } else { + std::cout << "Coverage: " << (float(cov.first)/float(cov.second)) << " (" << cov.first << " out of " << cov.second << " residues)" << std::endl; + } + + if (cov.first == 0) { + std::cout << "Global LDDT score: 0.0" << std::endl; + _num_tot_res = 0; + _num_con_res = 0; + _global_score = 0.0; + _score_calculated = true; + _score_valid = false; + } + + std::pair<int,int> total_ov=alg::LocalDistDiffTest(model_view, glob_dist_list, settings.cutoffs, settings.sequence_separation, settings.label); + Real lddt = static_cast<Real>(total_ov.first)/(static_cast<Real>(total_ov.second) ? static_cast<Real>(total_ov.second) : 1); + std::cout << "Global LDDT score: " << std::setprecision(4) << lddt << std::endl; + std::cout << "(" << std::fixed << total_ov.first << " conserved distances out of " << total_ov.second + << " checked, over " << settings.cutoffs.size() << " thresholds)" << std::endl; + _num_tot_res = total_ov.second ? total_ov.second : 1; + _num_con_res = total_ov.first; + _global_score = lddt; + _score_calculated = true; + _score_valid = true; +} + +void lDDTScorer::_GetLocallDDT(){ + if (!_score_calculated){ + _ComputelDDT(); + } + _local_scores = GetlDDTPerResidueStats(model, + glob_dist_list, + settings.structural_checks, + settings.label); + _has_local_scores = true; +} + + GlobalRDMap CreateDistanceList(const EntityView& ref,Real max_dist) { GlobalRDMap dist_list; @@ -772,17 +961,19 @@ void CleanlDDTReferences(std::vector<EntityView>& ref_list){ } GlobalRDMap PreparelDDTGlobalRDMap(const std::vector<EntityView>& ref_list, - lDDTSettings& settings){ + std::vector<Real>& cutoff_list, + int sequence_separation, + Real max_dist){ GlobalRDMap glob_dist_list; if (ref_list.size()==1) { std::cout << "Multi-reference mode: Off" << std::endl; - glob_dist_list = CreateDistanceList(ref_list[0], settings.radius); + glob_dist_list = CreateDistanceList(ref_list[0], max_dist); } else { std::cout << "Multi-reference mode: On" << std::endl; glob_dist_list = CreateDistanceListFromMultipleReferences(ref_list, - settings.cutoffs, - settings.sequence_separation, - settings.radius); + cutoff_list, + sequence_separation, + max_dist); } return glob_dist_list; @@ -831,7 +1022,10 @@ void CheckStructure(EntityView& ent, std::cout << "Distances shorter than tolerance are on average shorter by: " << std::fixed << std::setprecision(5) << clash_info.GetAverageOffset() << std::endl; } -std::vector<lDDTLocalScore> GetlDDTPerResidueStats(EntityHandle& model, GlobalRDMap& glob_dist_list, lDDTSettings& settings){ +std::vector<lDDTLocalScore> GetlDDTPerResidueStats(EntityHandle& model, + GlobalRDMap& glob_dist_list, + bool structural_checks, + String label){ std::vector<lDDTLocalScore> scores; EntityView outv = model.GetChainList()[0].Select("peptide=true"); for (ChainViewList::const_iterator ci = outv.GetChainList().begin(), @@ -844,7 +1038,7 @@ std::vector<lDDTLocalScore> GetlDDTPerResidueStats(EntityHandle& model, GlobalRD bool assessed = false; String assessed_string="No"; String quality_problems_string; - if (settings.structural_checks) { + if (structural_checks) { quality_problems_string="No"; } else { quality_problems_string="NA"; @@ -867,15 +1061,15 @@ std::vector<lDDTLocalScore> GetlDDTPerResidueStats(EntityHandle& model, GlobalRD } if (assessed==true) { - if (ritv.HasProp(settings.label)) { - lddt_local=ritv.GetFloatProp(settings.label); + if (ritv.HasProp(label)) { + lddt_local=ritv.GetFloatProp(label); std::stringstream stkeylddt; stkeylddt << std::fixed << std::setprecision(4) << lddt_local; lddt_local_string=stkeylddt.str(); - conserved_dist=ritv.GetIntProp(settings.label+"_conserved"); - total_dist=ritv.GetIntProp(settings.label+"_total"); + conserved_dist=ritv.GetIntProp(label+"_conserved"); + total_dist=ritv.GetIntProp(label+"_total"); } else { - std::cout << settings.label << std::endl; + std::cout << label << std::endl; lddt_local = 0; lddt_local_string="0.0000"; conserved_dist = 0; @@ -898,8 +1092,8 @@ std::vector<lDDTLocalScore> GetlDDTPerResidueStats(EntityHandle& model, GlobalRD return scores; } -void PrintlDDTPerResidueStats(std::vector<lDDTLocalScore>& scores, lDDTSettings& settings){ - if (settings.structural_checks) { +void PrintlDDTPerResidueStats(std::vector<lDDTLocalScore>& scores, bool structural_checks, int cutoffs_length){ + if (structural_checks) { std::cout << "Local LDDT Scores:" << std::endl; std::cout << "(A 'Yes' in the 'Quality Problems' column stands for problems" << std::endl; std::cout << "in the side-chain of a residue, while a 'Yes+' for problems" << std::endl; @@ -907,9 +1101,9 @@ void PrintlDDTPerResidueStats(std::vector<lDDTLocalScore>& scores, lDDTSettings& } else { std::cout << "Local LDDT Scores:" << std::endl; } - std::cout << lDDTLocalScore::GetHeader(settings.structural_checks, settings.cutoffs.size()) << std::endl; + std::cout << lDDTLocalScore::GetHeader(structural_checks, cutoffs_length) << std::endl; for (std::vector<lDDTLocalScore>::const_iterator sit = scores.begin(); sit != scores.end(); ++sit) { - std::cout << sit->ToString(settings.structural_checks) << std::endl; + std::cout << sit->ToString(structural_checks) << std::endl; } std::cout << std::endl; } diff --git a/modules/mol/alg/src/local_dist_diff_test.hh b/modules/mol/alg/src/local_dist_diff_test.hh index 21aee5a1d7a035ae21450b05c84212bc103a1b9d..ebcf71579a838422b8c5a80b35c3b66ac8c36084 100644 --- a/modules/mol/alg/src/local_dist_diff_test.hh +++ b/modules/mol/alg/src/local_dist_diff_test.hh @@ -20,19 +20,32 @@ #define OST_MOL_ALG_LOCAL_DIST_TEST_HH #include <ost/mol/alg/module_config.hh> +#include <ost/mol/entity_handle.hh> #include <ost/seq/alignment_handle.hh> #include <ost/mol/alg/distance_test_common.hh> #include <ost/mol/alg/filter_clashes.hh> namespace ost { namespace mol { namespace alg { +struct StereoChemicalProps +{ + bool is_valid; + ost::mol::alg::StereoChemicalParams bond_table; + ost::mol::alg::StereoChemicalParams angle_table; + ost::mol::alg::ClashingDistances nonbonded_table; + + StereoChemicalProps(); + StereoChemicalProps(ost::mol::alg::StereoChemicalParams& init_bond_table, + ost::mol::alg::StereoChemicalParams& init_angle_table, + ost::mol::alg::ClashingDistances& init_nonbonded_table); +}; + struct lDDTSettings { Real bond_tolerance; Real angle_tolerance; Real radius; int sequence_separation; String sel; - String parameter_file_path; bool structural_checks; bool consistency_checks; std::vector<Real> cutoffs; @@ -44,12 +57,10 @@ struct lDDTSettings { Real init_radius, int init_sequence_separation, String init_sel, - String init_parameter_file_path, bool init_structural_checks, bool init_consistency_checks, std::vector<Real>& init_cutoffs, String init_label); - void SetStereoChemicalParamsPath(const String& path=""); void PrintParameters(); std::string ToString(); }; @@ -76,10 +87,53 @@ struct lDDTLocalScore { int init_total_dist); String ToString(bool structural_checks) const; + String Repr() const; static String GetHeader(bool structural_checks, int cutoffs_length); }; +class lDDTScorer +{ + public: + lDDTSettings settings; + ost::mol::EntityHandle model; + std::vector<EntityHandle> references; + EntityView model_view; + std::vector<EntityView> references_view; + GlobalRDMap glob_dist_list; + StereoChemicalProps stereochemical_params; + + lDDTScorer(std::vector<EntityHandle>& init_references, + ost::mol::EntityHandle& init_model, + lDDTSettings& init_settings); + lDDTScorer(std::vector<EntityHandle>& init_references, + ost::mol::EntityHandle& init_model, + lDDTSettings& init_settings, + StereoChemicalProps& init_stereochemical_params); + Real GetGlobalScore(); + std::vector<lDDTLocalScore> GetLocalScores(); + int GetNumConservedResidues(); // number of conserved distances in the model + int GetNumTotalResidues(); // the number of total distances in the reference structure + void PrintPerResidueStats(); + bool IsValid(); + + private: + bool _score_calculated; + bool _score_valid; + bool _has_local_scores; + // number of conserved distances in the model and + // the number of total distances in the reference structure + int _num_con_res; + int _num_tot_res; + Real _global_score; + std::vector<lDDTLocalScore> _local_scores; + void _ComputelDDT(); + void _GetLocallDDT(); + void _CheckConsistency(); + void _PrepareReferences(); + void _PrepareGlobalRDMap(); +}; + std::pair<int,int> DLLEXPORT_OST_MOL_ALG ComputeCoverage(const EntityView& v,const GlobalRDMap& glob_dist_list); bool DLLEXPORT_OST_MOL_ALG IsResnumInGlobalRDMap(const ResNum& resnum, const GlobalRDMap& glob_dist_list); @@ -205,7 +259,9 @@ void DLLEXPORT_OST_MOL_ALG CleanlDDTReferences(std::vector<EntityView>& ref_list // Prepare GlobalRDMap from reference list GlobalRDMap DLLEXPORT_OST_MOL_ALG PreparelDDTGlobalRDMap( const std::vector<EntityView>& ref_list, - lDDTSettings& settings); + std::vector<Real>& cutoff_list, + int sequence_separation, + Real max_dist); void DLLEXPORT_OST_MOL_ALG CheckStructure(EntityView& ent, StereoChemicalParams& bond_table, @@ -216,10 +272,12 @@ void DLLEXPORT_OST_MOL_ALG CheckStructure(EntityView& ent, std::vector<lDDTLocalScore> DLLEXPORT_OST_MOL_ALG GetlDDTPerResidueStats(EntityHandle& model, GlobalRDMap& glob_dist_list, - lDDTSettings& settings); + bool structural_checks, + String label); void DLLEXPORT_OST_MOL_ALG PrintlDDTPerResidueStats(std::vector<lDDTLocalScore>& scores, - lDDTSettings& settings); + bool structural_checks, + int cutoffs_length); }}}