// Copyright 2024 DeepMind Technologies Limited // // AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of // this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/ // // To request access to the AlphaFold 3 model parameters, follow the process set // out at https://github.com/google-deepmind/alphafold3. You may only use these // if received directly from Google. Use is subject to terms of use available at // https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md #include #include "absl/container/flat_hash_map.h" #include "absl/log/check.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "alphafold3/parsers/cpp/cif_dict_lib.h" #include "pybind11/gil.h" #include "pybind11/pybind11.h" #include "pybind11/pytypes.h" #include "pybind11/stl.h" #include "pybind11_abseil/absl_casters.h" namespace alphafold3 { namespace { namespace py = pybind11; // If present, returns the _atom_site.type_symbol. If not, infers it using // _atom_site.label_comp_id (residue name), _atom_site.label_atom_id (atom name) // and the CCD. py::list GetOrInferTypeSymbol(const CifDict& mmcif, const py::object& atom_id_to_type_symbol) { const auto& type_symbol = mmcif["_atom_site.type_symbol"]; const int num_atom = mmcif["_atom_site.id"].size(); py::list patched_type_symbol(num_atom); if (type_symbol.empty()) { const auto& label_comp_id = mmcif["_atom_site.label_comp_id"]; const auto& label_atom_id = mmcif["_atom_site.label_atom_id"]; CHECK_EQ(label_comp_id.size(), num_atom); CHECK_EQ(label_atom_id.size(), num_atom); for (int i = 0; i < num_atom; i++) { patched_type_symbol[i] = atom_id_to_type_symbol(label_comp_id[i], label_atom_id[i]); } } else { for (int i = 0; i < num_atom; i++) { patched_type_symbol[i] = type_symbol[i]; } } return patched_type_symbol; } absl::flat_hash_map GetInternalToAuthorChainIdMap(const CifDict& mmcif) { const auto& label_asym_ids = mmcif["_atom_site.label_asym_id"]; const auto& auth_asym_ids = mmcif["_atom_site.auth_asym_id"]; CHECK_EQ(label_asym_ids.size(), auth_asym_ids.size()); absl::flat_hash_map mapping; for (size_t i = 0, num_rows = label_asym_ids.size(); i < num_rows; ++i) { // Use only the first internal_chain_id occurrence to generate the mapping. // It should not matter as there should not be a case where a single // internal chain ID would map to more than one author chain IDs (i.e. the // mapping should be injective). Since we need this method to be fast, we // choose not to check it. mapping.emplace(label_asym_ids[i], auth_asym_ids[i]); } return mapping; } } // namespace namespace py = pybind11; void RegisterModuleMmcifAtomSite(pybind11::module m) { m.def("get_or_infer_type_symbol", &GetOrInferTypeSymbol, py::arg("mmcif"), py::arg("atom_id_to_type_symbol")); m.def("get_internal_to_author_chain_id_map", &GetInternalToAuthorChainIdMap, py::arg("mmcif"), py::call_guard()); } } // namespace alphafold3