diff --git a/api/coot-molecule.cc b/api/coot-molecule.cc index 97deda596..6d906d474 100644 --- a/api/coot-molecule.cc +++ b/api/coot-molecule.cc @@ -196,6 +196,15 @@ coot::molecule_t::cid_to_residues(const std::string &atom_selection_cids) const return v; } +// can return null +mmdb::Residue * +coot::molecule_t::get_residue(const std::string &residue_cid) const { + + mmdb::Residue *residue_p = cid_to_residue(residue_cid); + return residue_p; +} + + // restore from (previous) backup diff --git a/api/coot-molecule.hh b/api/coot-molecule.hh index c337caa1a..f19cdc87c 100644 --- a/api/coot-molecule.hh +++ b/api/coot-molecule.hh @@ -597,6 +597,9 @@ namespace coot { // returns either the specified residue or null if not found mmdb::Residue *get_residue(const residue_spec_t &residue_spec) const; + // can return null + mmdb::Residue *get_residue(const std::string &residue_cid) const; + std::string get_residue_name(const residue_spec_t &residue_spec) const; bool have_unsaved_changes() const { return modification_info.have_unsaved_changes(); } diff --git a/api/molecules-container-nanobind.cc b/api/molecules-container-nanobind.cc index c06e53d0f..b14829696 100644 --- a/api/molecules-container-nanobind.cc +++ b/api/molecules-container-nanobind.cc @@ -6,14 +6,15 @@ #include #include -#include "molecules-container.hh" -#include "mini-mol/mini-mol-utils.hh" - #include "clipper/core/ramachandran.h" #include "clipper/clipper-ccp4.h" -#include "coot-utils/g_triangle.hh" #include "coords/mmdb-crystal.h" +#include "coot-utils/acedrg-types-for-residue.hh" +#include "coot-utils/g_triangle.hh" +#include "mini-mol/mini-mol-utils.hh" +#include "molecules-container.hh" + namespace nb = nanobind; @@ -257,6 +258,7 @@ NB_MODULE(chapi, m) { .def("geometry_init_standard",&molecules_container_t::geometry_init_standard) .def("get_active_atom",&molecules_container_t::get_active_atom) .def("get_acedrg_atom_types",&molecules_container_t::get_acedrg_atom_types) + .def("get_acedrg_atom_types_for_ligand",&molecules_container_t::get_acedrg_atom_types_for_ligand) .def("get_atom",&molecules_container_t::get_atom, nb::rv_policy::reference) .def("get_atom_using_cid",&molecules_container_t::get_atom_using_cid, nb::rv_policy::reference) .def("get_bonds_mesh",&molecules_container_t::get_bonds_mesh) @@ -556,6 +558,16 @@ NB_MODULE(chapi, m) { .def_ro("geom", &coot::instanced_mesh_t::geom) .def_ro("markup", &coot::instanced_mesh_t::markup) ; + nb::class_(m,"acedrg_types_for_bond_t") + .def_ro("atom_id_1", &coot::acedrg_types_for_bond_t::atom_id_1) + .def_ro("atom_id_2", &coot::acedrg_types_for_bond_t::atom_id_2) + .def_ro("atom_type_1", &coot::acedrg_types_for_bond_t::atom_type_1) + .def_ro("atom_type_2", &coot::acedrg_types_for_bond_t::atom_type_2) + .def_ro("bond_length", &coot::acedrg_types_for_bond_t::bond_length) + ; + nb::class_(m,"acedrg_types_for_residue_t") + .def_ro("bond_types", &coot::acedrg_types_for_residue_t::bond_types) + ; nb::class_(m,"phi_psi_t") .def("phi", &coot::util::phi_psi_t::phi) .def("psi", &coot::util::phi_psi_t::psi) diff --git a/api/molecules-container.cc b/api/molecules-container.cc index 2b50a0bcb..f58db3c44 100644 --- a/api/molecules-container.cc +++ b/api/molecules-container.cc @@ -5405,6 +5405,24 @@ molecules_container_t::get_acedrg_atom_types(const std::string &compound_id, int } +//! get acedrg types for ligand bonds +//! @return a vector of `acedrg_types_for_residue_t` +coot::acedrg_types_for_residue_t +molecules_container_t::get_acedrg_atom_types_for_ligand(int imol, const std::string &residue_cid) const { + + coot::acedrg_types_for_residue_t types; + + if (is_valid_model_molecule(imol)) { + mmdb::Residue *residue_p = molecules[imol].get_residue(residue_cid); + if (residue_p) { + int imol_enc = imol; + types = coot::get_acedrg_types_for_residue(residue_p, imol_enc, geom); + } + } + return types; +} + + //! export map molecule as glTF diff --git a/api/molecules-container.hh b/api/molecules-container.hh index 1bada00e7..4200b3506 100644 --- a/api/molecules-container.hh +++ b/api/molecules-container.hh @@ -669,6 +669,10 @@ public: //! on failure (atoms types are not in the dictionary or atom failure to look up the compound id)l std::vector > get_acedrg_atom_types(const std::string &compound_id, int imol_enc) const; + //! get acedrg types for ligand bonds + //! @return a vector of `acedrg_types_for_residue_t` + coot::acedrg_types_for_residue_t get_acedrg_atom_types_for_ligand(int imol, const std::string &residue_cid) const; + //! write a PNG for the given compound_id. imol can be IMOL_ENC_ANY //! //! Currently this function does nothing (drawing is done with the not-allowed cairo) diff --git a/api/test-molecules-container.cc b/api/test-molecules-container.cc index cac983600..60bb9b135 100644 --- a/api/test-molecules-container.cc +++ b/api/test-molecules-container.cc @@ -2,17 +2,18 @@ #include #include +#include +#include +#include + #define GLM_ENABLE_EXPERIMENTAL #include #include "MoleculesToTriangles/CXXClasses/MyMolecule.h" #include "molecules-container.hh" +#include "coot-utils/acedrg-types-for-residue.hh" #include "filo-tests.hh" #include "lucrezia-tests.hh" -#include -#include -#include - void starting_test(const char *func) { std::cout << "\nStarting " << func << "()" << std::endl; } @@ -5933,6 +5934,26 @@ int test_dictionary_acedrg_atom_types(molecules_container_t &mc) { return status; } +int test_dictionary_acedrg_atom_types_for_ligand(molecules_container_t &mc) { + + starting_test(__FUNCTION__); + int status = 0; + + mc.import_cif_dictionary("YXG-as-LIG.cif", coot::protein_geometry::IMOL_ENC_ANY); + int imol = mc.get_monomer_from_dictionary("LIG", coot::protein_geometry::IMOL_ENC_ANY, false); + coot::acedrg_types_for_residue_t types = mc.get_acedrg_atom_types_for_ligand(imol, "//A/1"); + + std::cout << "------------- types (bond) ----------- " << std::endl; + for (unsigned int i=0; i 10) status = 1; + return status; +} int test_template(molecules_container_t &mc) { @@ -6247,6 +6268,7 @@ int main(int argc, char **argv) { // status += run_test(test_import_LIG_dictionary, "Import LIG.cif", mc); // status += run_test(test_tricky_ligand_problem, "Tricky Ligand import/refine", mc); status += run_test(test_dictionary_acedrg_atom_types, "Acedrg atom types", mc); + status += run_test(test_dictionary_acedrg_atom_types_for_ligand, "Acedrg atom types for ligand", mc); if (status == n_tests) all_tests_status = 0; diff --git a/coot-utils/Makefile.am b/coot-utils/Makefile.am index f723b1267..6c8229cd4 100644 --- a/coot-utils/Makefile.am +++ b/coot-utils/Makefile.am @@ -44,7 +44,8 @@ pkginclude_HEADERS = peak-search.hh coot-trim.hh \ atom-tree.hh jed-flip.hh atom-vertex.hh merge-C-and-N-terminii.hh simple-mesh.hh vertex.hh g_triangle.hh \ cylinder.hh cylinder-with-rotation-translation.hh oct.hh prideout-octasphere.hh cmtz-interface.hh mtz-column-auto-read.hh \ pugixml.hpp pugiconfig.hpp find-water-baddies.hh voidp-buffer.hh parse-pisa.hh diff-diff-map-peaks.hh tiny_gltf.h json.hpp \ - stb_image.h stb_image_write.h glyco-tree.hh positron.hh mini-texture.hh texture-as-floats.hh pae.hh q-score.hh + stb_image.h stb_image_write.h glyco-tree.hh positron.hh mini-texture.hh texture-as-floats.hh pae.hh q-score.hh \ + acedrg-types-for-residue.hh pkgincludedir = $(includedir)/coot/coot-utils diff --git a/coot-utils/acedrg-types-for-residue.hh b/coot-utils/acedrg-types-for-residue.hh new file mode 100644 index 000000000..752a1a639 --- /dev/null +++ b/coot-utils/acedrg-types-for-residue.hh @@ -0,0 +1,46 @@ + +#ifndef ACEDRG_TYPES_FOR_RESIDUE_HH +#define ACEDRG_TYPES_FOR_RESIDUE_HH + +#include +#include + +namespace coot { + + class acedrg_types_for_bond_t { + public: + std::string atom_id_1; + std::string atom_id_2; + std::string atom_type_1; + std::string atom_type_2; + double bond_length; + acedrg_types_for_bond_t() : bond_length(-1) {} + acedrg_types_for_bond_t(const std::string &a11, const std::string &a12, const std::string &a21, const std::string &a22, + double bl) : atom_id_1(a11), atom_id_2(a12), atom_type_1(a21), atom_type_2(a22), + bond_length(bl) {} + }; + + class acedrg_types_for_angle_t { + public: + std::string atom_id_1; + std::string atom_id_2; + std::string atom_id_3; + std::string atom_type_1; + std::string atom_type_2; + std::string atom_type_3; + double angle; // radians + acedrg_types_for_angle_t(const std::string &a11, const std::string &a12, const std::string &a13, + const std::string &a21, const std::string &a22, const std::string &a23, + double a) : atom_id_1(a11), atom_id_2(a12), atom_id_3(a13), + atom_type_1(a21), atom_type_2(a22), atom_type_3(a23), + angle(a) {} + }; + + class acedrg_types_for_residue_t { + public: + std::vector bond_types; + }; + +} + +#endif // ACEDRG_TYPES_FOR_RESIDUE_HH diff --git a/coot-utils/coot-coord-extras.cc b/coot-utils/coot-coord-extras.cc index 357f3cdeb..cdeba3a42 100644 --- a/coot-utils/coot-coord-extras.cc +++ b/coot-utils/coot-coord-extras.cc @@ -21,6 +21,7 @@ */ +#include #include #include #include // for std::find @@ -28,6 +29,7 @@ #include #include +#include "acedrg-types-for-residue.hh" #include "string.h" #include "compat/coot-sysdep.h" @@ -2005,3 +2007,57 @@ coot::util::mutate_by_overlap(mmdb::Residue *residue_p, mmdb::Manager *mol, return status; } +coot::acedrg_types_for_residue_t +coot::get_acedrg_types_for_residue(mmdb::Residue *residue_p, int imol_enc, + const coot::protein_geometry &geom) { + + coot::acedrg_types_for_residue_t types; + std::string residue_type = residue_p->GetResName(); + auto r = geom.get_monomer_restraints(residue_type, imol_enc); + if (r.first) { + const auto &restraints = r.second; + for (unsigned int ib=0; ibGetAtomTable(residue_atoms, n_residue_atoms); + for (int iat=0; iatisTer()) { + std::string atom_name = at->GetAtomName(); + if (atom_name == atom_name_1) idx_1 = iat; + if (atom_name == atom_name_2) idx_2 = iat; + } + } + if (idx_1 != -1) { + if (idx_2 != -1) { + clipper::Coord_orth at_pos_1 = co(residue_atoms[idx_1]); + clipper::Coord_orth at_pos_2 = co(residue_atoms[idx_2]); + double bb = (at_pos_2 - at_pos_1).lengthsq(); + double bond_length = std::sqrt(bb); + + std::string type_1; + std::string type_2; + + for (unsigned int ii=0; ii