Upload folder using huggingface_hub (part 2)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- flax_model/alphafold3/structure/cpp/mmcif_altlocs.h +51 -0
- flax_model/alphafold3/structure/cpp/mmcif_atom_site.pyi +15 -0
- flax_model/alphafold3/structure/cpp/mmcif_atom_site_pybind.cc +83 -0
- flax_model/alphafold3/structure/cpp/mmcif_atom_site_pybind.h +24 -0
- flax_model/alphafold3/structure/cpp/mmcif_layout.h +146 -0
- flax_model/alphafold3/structure/cpp/mmcif_layout.pyi +18 -0
- flax_model/alphafold3/structure/cpp/mmcif_layout_lib.cc +213 -0
- flax_model/alphafold3/structure/cpp/mmcif_layout_pybind.cc +49 -0
- flax_model/alphafold3/structure/cpp/mmcif_layout_pybind.h +24 -0
- flax_model/alphafold3/structure/cpp/mmcif_struct_conn.h +34 -0
- flax_model/alphafold3/structure/cpp/mmcif_struct_conn.pyi +5 -0
- flax_model/alphafold3/structure/cpp/mmcif_struct_conn_lib.cc +380 -0
- flax_model/alphafold3/structure/cpp/mmcif_struct_conn_pybind.cc +68 -0
- flax_model/alphafold3/structure/cpp/mmcif_struct_conn_pybind.h +24 -0
- flax_model/alphafold3/structure/cpp/mmcif_utils.pyi +63 -0
- flax_model/alphafold3/structure/cpp/mmcif_utils_pybind.cc +787 -0
- flax_model/alphafold3/structure/cpp/mmcif_utils_pybind.h +24 -0
- flax_model/alphafold3/structure/cpp/string_array.pyi +42 -0
- flax_model/alphafold3/structure/cpp/string_array_pybind.cc +329 -0
- flax_model/alphafold3/structure/cpp/string_array_pybind.h +24 -0
- flax_model/alphafold3/structure/mmcif.py +321 -0
- flax_model/alphafold3/structure/parsing.py +1801 -0
- flax_model/alphafold3/structure/sterics.py +132 -0
- flax_model/alphafold3/structure/structure.py +0 -0
- flax_model/alphafold3/structure/structure_tables.py +811 -0
- flax_model/alphafold3/structure/table.py +555 -0
- flax_model/alphafold3/structure/test_utils.py +161 -0
- flax_model/alphafold3/test_data/__init__.py +0 -0
- flax_model/alphafold3/test_data/featurised_example.json +68 -0
- flax_model/alphafold3/test_data/miniature_databases/__init__.py +0 -0
- flax_model/alphafold3/test_data/miniature_databases/bfd-first_non_consensus_sequences__subsampled_1000.fasta +0 -0
- flax_model/alphafold3/test_data/miniature_databases/mgy_clusters__subsampled_1000.fa +0 -0
- flax_model/alphafold3/test_data/miniature_databases/nt_rna_2023_02_23_clust_seq_id_90_cov_80_rep_seq__subsampled_1000.fasta +0 -0
- flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/5y2e.cif +562 -0
- flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/6s61.cif +0 -0
- flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/6ydw.cif +0 -0
- flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/7rye.cif +893 -0
- flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/__init__.py +0 -0
- flax_model/alphafold3/test_data/miniature_databases/pdb_seqres_2022_09_28__subsampled_1000.fasta +0 -0
- flax_model/alphafold3/test_data/miniature_databases/rfam_14_4_clustered_rep_seq__subsampled_1000.fasta +0 -0
- flax_model/alphafold3/test_data/miniature_databases/rnacentral_active_seq_id_90_cov_80_linclust__subsampled_1000.fasta +0 -0
- flax_model/alphafold3/test_data/miniature_databases/uniprot_all__subsampled_1000.fasta +0 -0
- flax_model/alphafold3/test_data/miniature_databases/uniref90__subsampled_1000.fasta +0 -0
- flax_model/alphafold3/test_data/model_config.json +231 -0
- flax_model/alphafold3/version.py +13 -0
- inputs/7r6r_data.json +0 -0
- inputs/t1119_search.json +19 -0
- scripts/infer.sh +28 -0
- scripts/infer_jackhmmer.sh +53 -0
- scripts/infer_mmseqs.sh +42 -0
flax_model/alphafold3/structure/cpp/mmcif_altlocs.h
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_ALTLOCS_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_ALTLOCS_H_
|
| 15 |
+
|
| 16 |
+
#include <cstddef>
|
| 17 |
+
#include <cstdint>
|
| 18 |
+
#include <string>
|
| 19 |
+
#include <vector>
|
| 20 |
+
|
| 21 |
+
#include "absl/types/span.h"
|
| 22 |
+
#include "alphafold3/structure/cpp/mmcif_layout.h"
|
| 23 |
+
|
| 24 |
+
namespace alphafold3 {
|
| 25 |
+
|
| 26 |
+
// Returns the list of indices that should be kept after resolving alt-locs.
|
| 27 |
+
// 1) Partial Residue. Each cycle of alt-locs are resolved separately with the
|
| 28 |
+
// highest occupancy alt-loc. Tie-breaks are resolved alphabetically. See
|
| 29 |
+
// tests for examples.
|
| 30 |
+
// 2) Whole Residue. These are resolved in two passes.
|
| 31 |
+
// a) The residue with the highest occupancy is chosen.
|
| 32 |
+
// b) The locations for a given residue are resolved.
|
| 33 |
+
// All tie-breaks are resolved alphabetically. See tests for examples.
|
| 34 |
+
//
|
| 35 |
+
// Preconditions: layout and comp_ids, alt_ids, occupancies are all from same
|
| 36 |
+
// mmCIF file and chain_indices are monotonically increasing and less than
|
| 37 |
+
// layout.num_chains().
|
| 38 |
+
//
|
| 39 |
+
// comp_ids from '_atom_site.label_comp_id'.
|
| 40 |
+
// alt_ids from '_atom_site.label_alt_id'.
|
| 41 |
+
// occupancies from '_atom_site.occupancy'.
|
| 42 |
+
std::vector<std::uint64_t> ResolveMmcifAltLocs(
|
| 43 |
+
const MmcifLayout& layout, absl::Span<const std::string> comp_ids,
|
| 44 |
+
absl::Span<const std::string> atom_ids,
|
| 45 |
+
absl::Span<const std::string> alt_ids,
|
| 46 |
+
absl::Span<const std::string> occupancies,
|
| 47 |
+
absl::Span<const std::size_t> chain_indices);
|
| 48 |
+
|
| 49 |
+
} // namespace alphafold3
|
| 50 |
+
|
| 51 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_ALTLOCS_H_
|
flax_model/alphafold3/structure/cpp/mmcif_atom_site.pyi
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
from collections.abc import Callable
|
| 4 |
+
from flax_model.alphafold3.cpp import cif_dict
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def get_internal_to_author_chain_id_map(
|
| 8 |
+
mmcif: cif_dict.CifDict
|
| 9 |
+
) -> dict[str,str]: ...
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def get_or_infer_type_symbol(
|
| 13 |
+
mmcif: cif_dict.CifDict,
|
| 14 |
+
atom_id_to_type_symbol: Callable[[str, str], str],
|
| 15 |
+
) -> list[str]: ...
|
flax_model/alphafold3/structure/cpp/mmcif_atom_site_pybind.cc
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
//
|
| 3 |
+
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
//
|
| 6 |
+
// To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
// out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
// if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
#include <cstddef>
|
| 12 |
+
|
| 13 |
+
#include "absl/container/flat_hash_map.h"
|
| 14 |
+
#include "absl/log/check.h"
|
| 15 |
+
#include "absl/strings/string_view.h"
|
| 16 |
+
#include "absl/types/span.h"
|
| 17 |
+
#include "alphafold3/parsers/cpp/cif_dict_lib.h"
|
| 18 |
+
#include "pybind11/gil.h"
|
| 19 |
+
#include "pybind11/pybind11.h"
|
| 20 |
+
#include "pybind11/pytypes.h"
|
| 21 |
+
#include "pybind11/stl.h"
|
| 22 |
+
#include "pybind11_abseil/absl_casters.h"
|
| 23 |
+
|
| 24 |
+
namespace alphafold3 {
|
| 25 |
+
namespace {
|
| 26 |
+
namespace py = pybind11;
|
| 27 |
+
|
| 28 |
+
// If present, returns the _atom_site.type_symbol. If not, infers it using
|
| 29 |
+
// _atom_site.label_comp_id (residue name), _atom_site.label_atom_id (atom name)
|
| 30 |
+
// and the CCD.
|
| 31 |
+
py::list GetOrInferTypeSymbol(const CifDict& mmcif,
|
| 32 |
+
const py::object& atom_id_to_type_symbol) {
|
| 33 |
+
const auto& type_symbol = mmcif["_atom_site.type_symbol"];
|
| 34 |
+
const int num_atom = mmcif["_atom_site.id"].size();
|
| 35 |
+
py::list patched_type_symbol(num_atom);
|
| 36 |
+
if (type_symbol.empty()) {
|
| 37 |
+
const auto& label_comp_id = mmcif["_atom_site.label_comp_id"];
|
| 38 |
+
const auto& label_atom_id = mmcif["_atom_site.label_atom_id"];
|
| 39 |
+
CHECK_EQ(label_comp_id.size(), num_atom);
|
| 40 |
+
CHECK_EQ(label_atom_id.size(), num_atom);
|
| 41 |
+
for (int i = 0; i < num_atom; i++) {
|
| 42 |
+
patched_type_symbol[i] =
|
| 43 |
+
atom_id_to_type_symbol(label_comp_id[i], label_atom_id[i]);
|
| 44 |
+
}
|
| 45 |
+
} else {
|
| 46 |
+
for (int i = 0; i < num_atom; i++) {
|
| 47 |
+
patched_type_symbol[i] = type_symbol[i];
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
return patched_type_symbol;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
absl::flat_hash_map<absl::string_view, absl::string_view>
|
| 54 |
+
GetInternalToAuthorChainIdMap(const CifDict& mmcif) {
|
| 55 |
+
const auto& label_asym_ids = mmcif["_atom_site.label_asym_id"];
|
| 56 |
+
const auto& auth_asym_ids = mmcif["_atom_site.auth_asym_id"];
|
| 57 |
+
CHECK_EQ(label_asym_ids.size(), auth_asym_ids.size());
|
| 58 |
+
|
| 59 |
+
absl::flat_hash_map<absl::string_view, absl::string_view> mapping;
|
| 60 |
+
for (size_t i = 0, num_rows = label_asym_ids.size(); i < num_rows; ++i) {
|
| 61 |
+
// Use only the first internal_chain_id occurrence to generate the mapping.
|
| 62 |
+
// It should not matter as there should not be a case where a single
|
| 63 |
+
// internal chain ID would map to more than one author chain IDs (i.e. the
|
| 64 |
+
// mapping should be injective). Since we need this method to be fast, we
|
| 65 |
+
// choose not to check it.
|
| 66 |
+
mapping.emplace(label_asym_ids[i], auth_asym_ids[i]);
|
| 67 |
+
}
|
| 68 |
+
return mapping;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
} // namespace
|
| 72 |
+
|
| 73 |
+
namespace py = pybind11;
|
| 74 |
+
|
| 75 |
+
void RegisterModuleMmcifAtomSite(pybind11::module m) {
|
| 76 |
+
m.def("get_or_infer_type_symbol", &GetOrInferTypeSymbol, py::arg("mmcif"),
|
| 77 |
+
py::arg("atom_id_to_type_symbol"));
|
| 78 |
+
|
| 79 |
+
m.def("get_internal_to_author_chain_id_map", &GetInternalToAuthorChainIdMap,
|
| 80 |
+
py::arg("mmcif"), py::call_guard<py::gil_scoped_release>());
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
} // namespace alphafold3
|
flax_model/alphafold3/structure/cpp/mmcif_atom_site_pybind.h
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_ATOM_SITE_PYBIND_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_ATOM_SITE_PYBIND_H_
|
| 15 |
+
|
| 16 |
+
#include "pybind11/pybind11.h"
|
| 17 |
+
|
| 18 |
+
namespace alphafold3 {
|
| 19 |
+
|
| 20 |
+
void RegisterModuleMmcifAtomSite(pybind11::module m);
|
| 21 |
+
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_ATOM_SITE_PYBIND_H_
|
flax_model/alphafold3/structure/cpp/mmcif_layout.h
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_LAYOUT_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_LAYOUT_H_
|
| 15 |
+
|
| 16 |
+
#include <cstddef>
|
| 17 |
+
#include <cstdint>
|
| 18 |
+
#include <string>
|
| 19 |
+
#include <utility>
|
| 20 |
+
#include <vector>
|
| 21 |
+
|
| 22 |
+
#include "absl/status/statusor.h"
|
| 23 |
+
#include "absl/strings/string_view.h"
|
| 24 |
+
#include "absl/types/span.h"
|
| 25 |
+
#include "alphafold3/parsers/cpp/cif_dict_lib.h"
|
| 26 |
+
|
| 27 |
+
namespace alphafold3 {
|
| 28 |
+
|
| 29 |
+
// Holds the layout of a parsed mmCIF file.
|
| 30 |
+
class MmcifLayout {
|
| 31 |
+
public:
|
| 32 |
+
MmcifLayout(std::vector<std::size_t> chain_ends,
|
| 33 |
+
std::vector<std::size_t> residues, std::size_t model_offset,
|
| 34 |
+
std::size_t num_models)
|
| 35 |
+
: chain_ends_(std::move(chain_ends)),
|
| 36 |
+
residue_ends_(std::move(residues)),
|
| 37 |
+
model_offset_(model_offset),
|
| 38 |
+
num_models_(num_models) {}
|
| 39 |
+
|
| 40 |
+
// Reads a layout from a valid parsed mmCIF. If a valid model_id is provided
|
| 41 |
+
// the offsets will select that model from the mmCIF.
|
| 42 |
+
// If no model_id is specified, we calculate the layout of the first model
|
| 43 |
+
// only. Therefore it is a requirement that each model has identical atom
|
| 44 |
+
// layouts. An error is returned if the atom counts do not between models.
|
| 45 |
+
static absl::StatusOr<MmcifLayout> Create(const CifDict& mmcif,
|
| 46 |
+
absl::string_view model_id = "");
|
| 47 |
+
|
| 48 |
+
std::string ToDebugString() const;
|
| 49 |
+
|
| 50 |
+
// Returns the start index and one past the last residue index of a given
|
| 51 |
+
// chain. A chain_index of n refers to the n-th chain in the mmCIF. The
|
| 52 |
+
// returned residue indices are 0-based enumerations of residues in the
|
| 53 |
+
// _atom_site records, and therefore do not include missing residues.
|
| 54 |
+
std::pair<std::size_t, std::size_t> residue_range(
|
| 55 |
+
std::size_t chain_index) const {
|
| 56 |
+
if (chain_index > 0) {
|
| 57 |
+
return {chain_ends_[chain_index - 1], chain_ends_[chain_index]};
|
| 58 |
+
} else {
|
| 59 |
+
return {0, chain_ends_[0]};
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
// Returns the start index and one past the last index of a given residue.
|
| 64 |
+
// A residue_index of n refers to the n-th residue in the mmCIF, not
|
| 65 |
+
// including residues that are unresolved (i.e. only using _atom_site).
|
| 66 |
+
std::pair<std::size_t, std::size_t> atom_range(
|
| 67 |
+
std::size_t residue_index) const {
|
| 68 |
+
if (residue_index > 0) {
|
| 69 |
+
return {residue_ends_[residue_index - 1], residue_ends_[residue_index]};
|
| 70 |
+
} else {
|
| 71 |
+
return {model_offset_, residue_ends_[residue_index]};
|
| 72 |
+
}
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
// If model_id was provided during construction then this is 1, otherwise
|
| 76 |
+
// it is the number of models present in the mmCIF.
|
| 77 |
+
std::size_t num_models() const { return num_models_; }
|
| 78 |
+
// The number of atoms in the chosen model.
|
| 79 |
+
std::size_t num_atoms() const {
|
| 80 |
+
return residue_ends_.empty() ? 0 : residue_ends_.back() - model_offset_;
|
| 81 |
+
}
|
| 82 |
+
// The number of chains in the chosen model.
|
| 83 |
+
std::size_t num_chains() const { return chain_ends_.size(); }
|
| 84 |
+
// The number of residues in the chosen model, not counting unresolved
|
| 85 |
+
// residues.
|
| 86 |
+
std::size_t num_residues() const { return residue_ends_.size(); }
|
| 87 |
+
|
| 88 |
+
// Returns the first atom index that is part of the specified chain.
|
| 89 |
+
// The chain is specified using chain_index, which is a 0-based
|
| 90 |
+
// enumeration of the chains in the _atom_site table.
|
| 91 |
+
std::size_t atom_site_from_chain_index(std::size_t chain_index) const {
|
| 92 |
+
if (chain_index == 0) {
|
| 93 |
+
return model_offset_;
|
| 94 |
+
}
|
| 95 |
+
return atom_site_from_residue_index(chain_ends_[chain_index - 1]);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
// Returns the first atom index that is part of the specified residue.
|
| 99 |
+
// The residue is specified using residue_index, which is a 0-based
|
| 100 |
+
// enumeration of the residues in the _atom_site table.
|
| 101 |
+
std::size_t atom_site_from_residue_index(std::size_t residues_index) const {
|
| 102 |
+
if (residues_index == 0) {
|
| 103 |
+
return model_offset_;
|
| 104 |
+
}
|
| 105 |
+
return residue_ends_[residues_index - 1];
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
// One past last residue index of each chain. The residue index does not
|
| 109 |
+
// include unresolved residues and is a simple 0-based enumeration of the
|
| 110 |
+
// residues in _atom_site table.
|
| 111 |
+
const std::vector<std::size_t>& chains() const { return chain_ends_; }
|
| 112 |
+
|
| 113 |
+
// Indices of the first atom of each chain. Note that this returns atom
|
| 114 |
+
// indices (like residue_starts()), not residue indices (like chains()).
|
| 115 |
+
std::vector<std::size_t> chain_starts() const;
|
| 116 |
+
|
| 117 |
+
// One past last atom index of each residue.
|
| 118 |
+
const std::vector<std::size_t>& residues() const { return residue_ends_; }
|
| 119 |
+
|
| 120 |
+
// Indices of the first atom of each residue.
|
| 121 |
+
std::vector<std::size_t> residue_starts() const {
|
| 122 |
+
std::vector<std::size_t> residue_starts;
|
| 123 |
+
if (!residue_ends_.empty()) {
|
| 124 |
+
residue_starts.reserve(residue_ends_.size());
|
| 125 |
+
residue_starts.push_back(model_offset_);
|
| 126 |
+
residue_starts.insert(residue_starts.end(), residue_ends_.begin(),
|
| 127 |
+
residue_ends_.end() - 1);
|
| 128 |
+
}
|
| 129 |
+
return residue_starts;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
// The first atom index that is part of the specified model.
|
| 133 |
+
std::size_t model_offset() const { return model_offset_; }
|
| 134 |
+
|
| 135 |
+
void Filter(absl::Span<const std::uint64_t> keep_indices);
|
| 136 |
+
|
| 137 |
+
private:
|
| 138 |
+
std::vector<std::size_t> chain_ends_;
|
| 139 |
+
std::vector<std::size_t> residue_ends_;
|
| 140 |
+
std::size_t model_offset_;
|
| 141 |
+
std::size_t num_models_;
|
| 142 |
+
};
|
| 143 |
+
|
| 144 |
+
} // namespace alphafold3
|
| 145 |
+
|
| 146 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_LAYOUT_H_
|
flax_model/alphafold3/structure/cpp/mmcif_layout.pyi
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
from flax_model.alphafold3.cpp import cif_dict
|
| 4 |
+
|
| 5 |
+
class MmcifLayout:
|
| 6 |
+
def atom_range(self, residue_index: int) -> tuple[int, int]: ...
|
| 7 |
+
def chain_starts(self) -> list[int]: ...
|
| 8 |
+
def chains(self) -> list[int]: ...
|
| 9 |
+
def model_offset(self) -> int: ...
|
| 10 |
+
def num_atoms(self) -> int: ...
|
| 11 |
+
def num_chains(self) -> int: ...
|
| 12 |
+
def num_models(self) -> int: ...
|
| 13 |
+
def num_residues(self) -> int: ...
|
| 14 |
+
def residue_range(self, chain_index: int) -> tuple[int, int]: ...
|
| 15 |
+
def residue_starts(self) -> list[int]: ...
|
| 16 |
+
def residues(self) -> list[int]: ...
|
| 17 |
+
|
| 18 |
+
def from_mmcif(mmcif: cif_dict.CifDict, model_id: str = ...) -> MmcifLayout: ...
|
flax_model/alphafold3/structure/cpp/mmcif_layout_lib.cc
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
//
|
| 3 |
+
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
//
|
| 6 |
+
// To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
// out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
// if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
#include <algorithm>
|
| 12 |
+
#include <cstddef>
|
| 13 |
+
#include <cstdint>
|
| 14 |
+
#include <functional>
|
| 15 |
+
#include <iterator>
|
| 16 |
+
#include <string>
|
| 17 |
+
#include <utility>
|
| 18 |
+
#include <vector>
|
| 19 |
+
|
| 20 |
+
#include "absl/algorithm/container.h"
|
| 21 |
+
#include "absl/status/status.h"
|
| 22 |
+
#include "absl/status/statusor.h"
|
| 23 |
+
#include "absl/strings/str_cat.h"
|
| 24 |
+
#include "absl/strings/str_format.h"
|
| 25 |
+
#include "absl/strings/string_view.h"
|
| 26 |
+
#include "absl/types/span.h"
|
| 27 |
+
#include "alphafold3/parsers/cpp/cif_dict_lib.h"
|
| 28 |
+
#include "alphafold3/structure/cpp/mmcif_layout.h"
|
| 29 |
+
|
| 30 |
+
namespace alphafold3 {
|
| 31 |
+
|
| 32 |
+
std::string MmcifLayout::ToDebugString() const {
|
| 33 |
+
return absl::StrFormat(
|
| 34 |
+
"MmcifLayout(models=%d, chains=%d, num_residues=%d, atoms=%d)",
|
| 35 |
+
num_models(), num_chains(), num_residues(), num_atoms());
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
// Changes layout to match keep_indices removing empty chains/residues.
|
| 39 |
+
void MmcifLayout::Filter(absl::Span<const std::uint64_t> keep_indices) {
|
| 40 |
+
if (num_chains() == 0) {
|
| 41 |
+
return;
|
| 42 |
+
}
|
| 43 |
+
// Update residue indices.
|
| 44 |
+
auto keep_it = absl::c_lower_bound(keep_indices, residue_ends_.front());
|
| 45 |
+
for (auto& residue : residue_ends_) {
|
| 46 |
+
while (keep_it != keep_indices.end() && *keep_it < residue) {
|
| 47 |
+
++keep_it;
|
| 48 |
+
}
|
| 49 |
+
residue = std::distance(keep_indices.begin(), keep_it);
|
| 50 |
+
}
|
| 51 |
+
// Unique residue_ends_ with updating chains.
|
| 52 |
+
auto first = residue_ends_.begin();
|
| 53 |
+
auto tail = first;
|
| 54 |
+
std::size_t num_skipped = 0;
|
| 55 |
+
std::size_t current = 0;
|
| 56 |
+
for (std::size_t& chain_end : chain_ends_) {
|
| 57 |
+
for (auto e = residue_ends_.begin() + chain_end; first != e; ++first) {
|
| 58 |
+
std::size_t next = *first;
|
| 59 |
+
*tail = next;
|
| 60 |
+
if (current != next) {
|
| 61 |
+
current = next;
|
| 62 |
+
++tail;
|
| 63 |
+
} else {
|
| 64 |
+
++num_skipped;
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
chain_end -= num_skipped;
|
| 68 |
+
}
|
| 69 |
+
residue_ends_.erase(tail, residue_ends_.end());
|
| 70 |
+
|
| 71 |
+
current = 0;
|
| 72 |
+
chain_ends_.erase(std::remove_if(chain_ends_.begin(), chain_ends_.end(),
|
| 73 |
+
[¤t](std::size_t next) {
|
| 74 |
+
bool result = current == next;
|
| 75 |
+
current = next;
|
| 76 |
+
return result;
|
| 77 |
+
}),
|
| 78 |
+
chain_ends_.end());
|
| 79 |
+
model_offset_ = 0;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
absl::StatusOr<MmcifLayout> MmcifLayout::Create(const CifDict& mmcif,
|
| 83 |
+
absl::string_view model_id) {
|
| 84 |
+
auto model_ids = mmcif["_atom_site.pdbx_PDB_model_num"];
|
| 85 |
+
auto chain_ids = mmcif["_atom_site.label_asym_id"]; // chain ID.
|
| 86 |
+
auto label_seq_ids = mmcif["_atom_site.label_seq_id"]; // residue ID.
|
| 87 |
+
auto auth_seq_ids = mmcif["_atom_site.auth_seq_id"]; // author residue ID.
|
| 88 |
+
auto insertion_codes = mmcif["_atom_site.pdbx_PDB_ins_code"];
|
| 89 |
+
|
| 90 |
+
if (model_ids.size() != chain_ids.size() ||
|
| 91 |
+
model_ids.size() != label_seq_ids.size() ||
|
| 92 |
+
(model_ids.size() != auth_seq_ids.size() && !auth_seq_ids.empty()) ||
|
| 93 |
+
(model_ids.size() != insertion_codes.size() &&
|
| 94 |
+
!insertion_codes.empty())) {
|
| 95 |
+
return absl::InvalidArgumentError(absl::StrCat(
|
| 96 |
+
"Invalid _atom_site table.", //
|
| 97 |
+
" len(_atom_site.pdbx_PDB_model_num): ", model_ids.size(),
|
| 98 |
+
" len(_atom_site.label_asym_id): ", chain_ids.size(),
|
| 99 |
+
" len(_atom_site.label_seq_id): ", label_seq_ids.size(),
|
| 100 |
+
" len(_atom_site.auth_seq_id): ", auth_seq_ids.size(),
|
| 101 |
+
" len(_atom_site.pdbx_PDB_ins_code): ", insertion_codes.size()));
|
| 102 |
+
}
|
| 103 |
+
std::size_t num_atoms = model_ids.size();
|
| 104 |
+
if (num_atoms == 0) {
|
| 105 |
+
return MmcifLayout({}, {}, 0, 0);
|
| 106 |
+
}
|
| 107 |
+
std::size_t model_offset = 0;
|
| 108 |
+
std::size_t num_models;
|
| 109 |
+
std::size_t num_atoms_per_model;
|
| 110 |
+
if (model_id.empty()) {
|
| 111 |
+
absl::string_view first_model_id = model_ids.front();
|
| 112 |
+
|
| 113 |
+
// Binary search for where the first model ends.
|
| 114 |
+
num_atoms_per_model = std::distance(
|
| 115 |
+
model_ids.begin(),
|
| 116 |
+
absl::c_upper_bound(model_ids, first_model_id, std::not_equal_to<>{}));
|
| 117 |
+
if (num_atoms % num_atoms_per_model != 0) {
|
| 118 |
+
return absl::InvalidArgumentError(absl::StrCat(
|
| 119 |
+
"Each model must have the same number of atoms: (", num_atoms, " % ",
|
| 120 |
+
num_atoms_per_model, " == ", num_atoms % num_atoms_per_model, ")."));
|
| 121 |
+
}
|
| 122 |
+
num_models = num_atoms / num_atoms_per_model;
|
| 123 |
+
// Test boundary conditions for each model hold.
|
| 124 |
+
for (std::size_t i = 1; i < num_models; ++i) {
|
| 125 |
+
if ((model_ids[i * num_atoms_per_model] !=
|
| 126 |
+
model_ids[(i + 1) * num_atoms_per_model - 1]) ||
|
| 127 |
+
(model_ids[i * num_atoms_per_model - 1] ==
|
| 128 |
+
model_ids[i * num_atoms_per_model])) {
|
| 129 |
+
return absl::InvalidArgumentError(
|
| 130 |
+
absl::StrCat("Each model must have the same number of atoms: (",
|
| 131 |
+
num_atoms, " % ", num_atoms_per_model,
|
| 132 |
+
" == ", num_atoms % num_atoms_per_model, ")."));
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
} else {
|
| 136 |
+
num_models = 1;
|
| 137 |
+
model_offset =
|
| 138 |
+
std::distance(model_ids.begin(), absl::c_find(model_ids, model_id));
|
| 139 |
+
if (model_offset == model_ids.size()) {
|
| 140 |
+
return absl::InvalidArgumentError(
|
| 141 |
+
absl::StrCat("Unknown model_id: ", model_id));
|
| 142 |
+
}
|
| 143 |
+
model_ids.remove_prefix(model_offset);
|
| 144 |
+
chain_ids.remove_prefix(model_offset);
|
| 145 |
+
label_seq_ids.remove_prefix(model_offset);
|
| 146 |
+
if (!auth_seq_ids.empty()) auth_seq_ids.remove_prefix(model_offset);
|
| 147 |
+
if (!insertion_codes.empty()) insertion_codes.remove_prefix(model_offset);
|
| 148 |
+
|
| 149 |
+
num_atoms_per_model = std::distance(
|
| 150 |
+
model_ids.begin(), std::upper_bound(model_ids.begin(), model_ids.end(),
|
| 151 |
+
model_id, std::not_equal_to<>{}));
|
| 152 |
+
num_atoms = num_atoms_per_model;
|
| 153 |
+
}
|
| 154 |
+
std::vector<std::size_t> residues;
|
| 155 |
+
std::vector<std::size_t> chains;
|
| 156 |
+
absl::string_view chain_id = chain_ids.front();
|
| 157 |
+
if (!auth_seq_ids.empty() && !insertion_codes.empty()) {
|
| 158 |
+
// If author residue IDs are present then these are preferred to
|
| 159 |
+
// label residue IDs because they work for multi-residue ligands (which
|
| 160 |
+
// are given constant "." label residue IDs).
|
| 161 |
+
// NB: Author residue IDs require both the auth_seq_id and the insertion
|
| 162 |
+
// code to be unique.
|
| 163 |
+
absl::string_view auth_seq_id = auth_seq_ids.front();
|
| 164 |
+
absl::string_view insertion_code = insertion_codes.front();
|
| 165 |
+
for (std::size_t i = 1; i < num_atoms_per_model; ++i) {
|
| 166 |
+
if (absl::string_view current_chain_id = chain_ids[i];
|
| 167 |
+
current_chain_id != chain_id) {
|
| 168 |
+
residues.push_back(i + model_offset);
|
| 169 |
+
chains.push_back(residues.size());
|
| 170 |
+
chain_id = current_chain_id;
|
| 171 |
+
auth_seq_id = auth_seq_ids[i];
|
| 172 |
+
insertion_code = insertion_codes[i];
|
| 173 |
+
} else if (absl::string_view current_seq_id = auth_seq_ids[i],
|
| 174 |
+
current_insertion_code = insertion_codes[i];
|
| 175 |
+
insertion_code != current_insertion_code ||
|
| 176 |
+
auth_seq_id != current_seq_id) {
|
| 177 |
+
residues.push_back(i + model_offset);
|
| 178 |
+
auth_seq_id = current_seq_id;
|
| 179 |
+
insertion_code = current_insertion_code;
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
} else {
|
| 183 |
+
absl::string_view label_seq_id = label_seq_ids.front();
|
| 184 |
+
for (std::size_t i = 1; i < num_atoms_per_model; ++i) {
|
| 185 |
+
if (absl::string_view current_chain_id = chain_ids[i];
|
| 186 |
+
current_chain_id != chain_id) {
|
| 187 |
+
residues.push_back(i + model_offset);
|
| 188 |
+
chains.push_back(residues.size());
|
| 189 |
+
chain_id = current_chain_id;
|
| 190 |
+
label_seq_id = label_seq_ids[i];
|
| 191 |
+
} else if (absl::string_view current_seq_id = label_seq_ids[i];
|
| 192 |
+
label_seq_id != current_seq_id) {
|
| 193 |
+
residues.push_back(i + model_offset);
|
| 194 |
+
label_seq_id = current_seq_id;
|
| 195 |
+
}
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
residues.push_back(num_atoms_per_model + model_offset);
|
| 199 |
+
chains.push_back(residues.size());
|
| 200 |
+
return MmcifLayout(std::move(chains), std::move(residues), model_offset,
|
| 201 |
+
num_models);
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
std::vector<std::size_t> MmcifLayout::chain_starts() const {
|
| 205 |
+
std::vector<std::size_t> chain_starts;
|
| 206 |
+
chain_starts.reserve(chain_ends_.size());
|
| 207 |
+
for (std::size_t index = 0; index < chain_ends_.size(); ++index) {
|
| 208 |
+
chain_starts.push_back(atom_site_from_chain_index(index));
|
| 209 |
+
}
|
| 210 |
+
return chain_starts;
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
} // namespace alphafold3
|
flax_model/alphafold3/structure/cpp/mmcif_layout_pybind.cc
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
//
|
| 3 |
+
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
//
|
| 6 |
+
// To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
// out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
// if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
#include "alphafold3/structure/cpp/mmcif_layout.h"
|
| 12 |
+
#include "pybind11/pybind11.h"
|
| 13 |
+
#include "pybind11/pytypes.h"
|
| 14 |
+
#include "pybind11/stl.h"
|
| 15 |
+
|
| 16 |
+
namespace alphafold3 {
|
| 17 |
+
|
| 18 |
+
namespace py = pybind11;
|
| 19 |
+
|
| 20 |
+
void RegisterModuleMmcifLayout(pybind11::module m) {
|
| 21 |
+
py::class_<MmcifLayout>(m, "MmcifLayout")
|
| 22 |
+
.def("__str__", &MmcifLayout::ToDebugString)
|
| 23 |
+
.def("num_models", &MmcifLayout::num_models)
|
| 24 |
+
.def("num_chains", &MmcifLayout::num_chains)
|
| 25 |
+
.def("num_residues", &MmcifLayout::num_residues)
|
| 26 |
+
.def("num_atoms", &MmcifLayout::num_atoms)
|
| 27 |
+
.def("residue_range", &MmcifLayout::residue_range, py::arg("chain_index"))
|
| 28 |
+
.def("atom_range", &MmcifLayout::atom_range, py::arg("residue_index"))
|
| 29 |
+
.def("chains", &MmcifLayout::chains,
|
| 30 |
+
py::doc("Returns a list of indices one past the last residue of "
|
| 31 |
+
"each chain."))
|
| 32 |
+
.def(
|
| 33 |
+
"chain_starts", &MmcifLayout::chain_starts,
|
| 34 |
+
py::doc("Returns a list of indices of the first atom of each chain."))
|
| 35 |
+
.def("residues", &MmcifLayout::residues,
|
| 36 |
+
py::doc("Returns a list of indices one past the last atom of each "
|
| 37 |
+
"residue."))
|
| 38 |
+
.def("residue_starts", &MmcifLayout::residue_starts,
|
| 39 |
+
py::doc(
|
| 40 |
+
"Returns a list of indices of the first atom of each residue."))
|
| 41 |
+
.def("model_offset", &MmcifLayout::model_offset,
|
| 42 |
+
py::doc("Returns the first atom index that is part of the specified "
|
| 43 |
+
"model."));
|
| 44 |
+
|
| 45 |
+
m.def("from_mmcif", &MmcifLayout::Create, py::arg("mmcif"),
|
| 46 |
+
py::arg("model_id") = "");
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
} // namespace alphafold3
|
flax_model/alphafold3/structure/cpp/mmcif_layout_pybind.h
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_LAYOUT_PYBIND_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_LAYOUT_PYBIND_H_
|
| 15 |
+
|
| 16 |
+
#include "pybind11/pybind11.h"
|
| 17 |
+
|
| 18 |
+
namespace alphafold3 {
|
| 19 |
+
|
| 20 |
+
void RegisterModuleMmcifLayout(pybind11::module m);
|
| 21 |
+
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_LAYOUT_PYBIND_H_
|
flax_model/alphafold3/structure/cpp/mmcif_struct_conn.h
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_STRUCT_CONN_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_STRUCT_CONN_H_
|
| 15 |
+
|
| 16 |
+
#include <utility>
|
| 17 |
+
#include <vector>
|
| 18 |
+
|
| 19 |
+
#include "absl/status/statusor.h"
|
| 20 |
+
#include "absl/strings/string_view.h"
|
| 21 |
+
#include "alphafold3/parsers/cpp/cif_dict_lib.h"
|
| 22 |
+
|
| 23 |
+
namespace alphafold3 {
|
| 24 |
+
|
| 25 |
+
// Returns a pair of atom indices for each row in the bonds table (aka
|
| 26 |
+
// _struct_conn). The indices are simple 0-based indexes into the columns of
|
| 27 |
+
// the _atom_site table in the input mmCIF, and do not necessarily correspond
|
| 28 |
+
// to the values in _atom_site.id, or any other column.
|
| 29 |
+
absl::StatusOr<std::pair<std::vector<std::size_t>, std::vector<std::size_t>>>
|
| 30 |
+
GetBondAtomIndices(const CifDict& mmcif, absl::string_view model_id);
|
| 31 |
+
|
| 32 |
+
} // namespace alphafold3
|
| 33 |
+
|
| 34 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_STRUCT_CONN_H_
|
flax_model/alphafold3/structure/cpp/mmcif_struct_conn.pyi
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
from flax_model.alphafold3.cpp import cif_dict
|
| 4 |
+
|
| 5 |
+
def get_bond_atom_indices(mmcif_dict: cif_dict.CifDict, model_id: str) -> tuple[list[int],list[int]]: ...
|
flax_model/alphafold3/structure/cpp/mmcif_struct_conn_lib.cc
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
//
|
| 3 |
+
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
//
|
| 6 |
+
// To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
// out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
// if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
#include <cstddef>
|
| 12 |
+
#include <iterator>
|
| 13 |
+
#include <optional>
|
| 14 |
+
#include <string>
|
| 15 |
+
#include <utility>
|
| 16 |
+
#include <vector>
|
| 17 |
+
|
| 18 |
+
#include "absl/algorithm/container.h"
|
| 19 |
+
#include "absl/container/flat_hash_map.h"
|
| 20 |
+
#include "absl/container/flat_hash_set.h"
|
| 21 |
+
#include "absl/status/status.h"
|
| 22 |
+
#include "absl/status/statusor.h"
|
| 23 |
+
#include "absl/strings/str_cat.h"
|
| 24 |
+
#include "absl/strings/string_view.h"
|
| 25 |
+
#include "absl/types/span.h"
|
| 26 |
+
#include "alphafold3/parsers/cpp/cif_dict_lib.h"
|
| 27 |
+
#include "alphafold3/structure/cpp/mmcif_struct_conn.h"
|
| 28 |
+
|
| 29 |
+
namespace alphafold3 {
|
| 30 |
+
|
| 31 |
+
namespace {
|
| 32 |
+
|
| 33 |
+
struct AtomId {
|
| 34 |
+
absl::string_view chain_id;
|
| 35 |
+
absl::string_view res_id_1;
|
| 36 |
+
absl::string_view res_id_2;
|
| 37 |
+
absl::string_view atom_name;
|
| 38 |
+
absl::string_view alt_id;
|
| 39 |
+
|
| 40 |
+
friend bool operator==(const AtomId&, const AtomId&) = default;
|
| 41 |
+
template <typename H>
|
| 42 |
+
friend H AbslHashValue(H h, const AtomId& m) {
|
| 43 |
+
return H::combine(std::move(h), m.chain_id, m.res_id_1, m.res_id_2,
|
| 44 |
+
m.atom_name, m.alt_id);
|
| 45 |
+
}
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
using StringArrayRef = absl::Span<const std::string>;
|
| 49 |
+
using BondIndexByAtom = absl::flat_hash_map<AtomId, std::vector<std::size_t>>;
|
| 50 |
+
using BondAtomIndices = std::vector<std::size_t>;
|
| 51 |
+
|
| 52 |
+
// Returns whether each container is the same size.
|
| 53 |
+
template <typename C, typename... Cs>
|
| 54 |
+
bool AreSameSize(const C& c, const Cs&... cs) {
|
| 55 |
+
return ((c.size() == cs.size()) && ...);
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
struct ColumnSpec {
|
| 59 |
+
absl::string_view chain_id_col;
|
| 60 |
+
absl::string_view res_id_1_col;
|
| 61 |
+
absl::string_view res_id_2_col;
|
| 62 |
+
absl::string_view atom_name_col;
|
| 63 |
+
std::optional<absl::string_view> alt_id_col; // Not used by OpenMM.
|
| 64 |
+
};
|
| 65 |
+
|
| 66 |
+
class AtomColumns {
|
| 67 |
+
public:
|
| 68 |
+
static absl::StatusOr<AtomColumns> Create(const CifDict& mmcif,
|
| 69 |
+
const ColumnSpec& column_spec) {
|
| 70 |
+
StringArrayRef chain_id = mmcif[column_spec.chain_id_col];
|
| 71 |
+
StringArrayRef res_id_1 = mmcif[column_spec.res_id_1_col];
|
| 72 |
+
StringArrayRef res_id_2 = mmcif[column_spec.res_id_2_col];
|
| 73 |
+
StringArrayRef atom_name = mmcif[column_spec.atom_name_col];
|
| 74 |
+
if (!AreSameSize(chain_id, res_id_1, res_id_2, atom_name)) {
|
| 75 |
+
return absl::InvalidArgumentError(absl::StrCat(
|
| 76 |
+
"Atom columns are not the same size. ", //
|
| 77 |
+
"len(", column_spec.chain_id_col, ")=", chain_id.size(), //
|
| 78 |
+
", len(", column_spec.res_id_1_col, ")=", res_id_1.size(), //
|
| 79 |
+
", len(", column_spec.res_id_2_col, ")=", res_id_2.size(), //
|
| 80 |
+
", len(", column_spec.atom_name_col, ")=", atom_name.size(), //
|
| 81 |
+
"."));
|
| 82 |
+
}
|
| 83 |
+
if (column_spec.alt_id_col.has_value()) {
|
| 84 |
+
StringArrayRef alt_id = mmcif[*column_spec.alt_id_col];
|
| 85 |
+
if (!AreSameSize(alt_id, chain_id)) {
|
| 86 |
+
return absl::InvalidArgumentError(absl::StrCat(
|
| 87 |
+
"Atom columns are not the same size. ", //
|
| 88 |
+
"len(", column_spec.chain_id_col, ")=", chain_id.size(), //
|
| 89 |
+
", len(", *column_spec.alt_id_col, ")=", alt_id.size(), //
|
| 90 |
+
"."));
|
| 91 |
+
}
|
| 92 |
+
return AtomColumns(chain_id, res_id_1, res_id_2, atom_name, alt_id,
|
| 93 |
+
column_spec);
|
| 94 |
+
} else {
|
| 95 |
+
return AtomColumns(chain_id, res_id_1, res_id_2, atom_name, std::nullopt,
|
| 96 |
+
column_spec);
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
inline std::size_t size() const { return size_; }
|
| 101 |
+
|
| 102 |
+
absl::string_view GetNormalizedAltId(const std::size_t index) const {
|
| 103 |
+
constexpr absl::string_view kFullStop = ".";
|
| 104 |
+
if (alt_id_.has_value()) {
|
| 105 |
+
absl::string_view alt_id = (*alt_id_)[index];
|
| 106 |
+
return alt_id == "?" ? kFullStop : alt_id;
|
| 107 |
+
} else {
|
| 108 |
+
return kFullStop;
|
| 109 |
+
}
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
AtomId GetAtom(const std::size_t index) const {
|
| 113 |
+
return {.chain_id = chain_id_[index],
|
| 114 |
+
.res_id_1 = res_id_1_[index],
|
| 115 |
+
.res_id_2 = res_id_2_[index],
|
| 116 |
+
.atom_name = atom_name_[index],
|
| 117 |
+
.alt_id = GetNormalizedAltId(index)};
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
std::string GetAtomString(const std::size_t index) const {
|
| 121 |
+
std::string alt_id_col;
|
| 122 |
+
if (column_spec_.alt_id_col.has_value()) {
|
| 123 |
+
alt_id_col = *column_spec_.alt_id_col;
|
| 124 |
+
} else {
|
| 125 |
+
alt_id_col = "default label_alt_id";
|
| 126 |
+
}
|
| 127 |
+
return absl::StrCat(
|
| 128 |
+
column_spec_.chain_id_col, "=", chain_id_[index], ", ", //
|
| 129 |
+
column_spec_.res_id_1_col, "=", res_id_1_[index], ", ", //
|
| 130 |
+
column_spec_.res_id_2_col, "=", res_id_2_[index], ", ", //
|
| 131 |
+
column_spec_.atom_name_col, "=", atom_name_[index], ", ", //
|
| 132 |
+
alt_id_col, "=", GetNormalizedAltId(index)); //
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
private:
|
| 136 |
+
AtomColumns(StringArrayRef chain_id, StringArrayRef res_id_1,
|
| 137 |
+
StringArrayRef res_id_2, StringArrayRef atom_name,
|
| 138 |
+
std::optional<StringArrayRef> alt_id,
|
| 139 |
+
const ColumnSpec& column_spec)
|
| 140 |
+
: chain_id_(chain_id),
|
| 141 |
+
res_id_1_(res_id_1),
|
| 142 |
+
res_id_2_(res_id_2),
|
| 143 |
+
atom_name_(atom_name),
|
| 144 |
+
alt_id_(alt_id),
|
| 145 |
+
column_spec_(column_spec),
|
| 146 |
+
size_(chain_id.size()) {}
|
| 147 |
+
StringArrayRef chain_id_;
|
| 148 |
+
StringArrayRef res_id_1_;
|
| 149 |
+
StringArrayRef res_id_2_;
|
| 150 |
+
StringArrayRef atom_name_;
|
| 151 |
+
std::optional<StringArrayRef> alt_id_;
|
| 152 |
+
ColumnSpec column_spec_;
|
| 153 |
+
std::size_t size_;
|
| 154 |
+
};
|
| 155 |
+
|
| 156 |
+
// Adds the atom index to any rows in the bond table involving that atom.
|
| 157 |
+
absl::Status FillInBondsForAtom(const BondIndexByAtom& bond_index_by_atom,
|
| 158 |
+
const AtomId& atom,
|
| 159 |
+
const std::size_t atom_index,
|
| 160 |
+
BondAtomIndices& bond_atom_indices) {
|
| 161 |
+
if (auto bond_index_it = bond_index_by_atom.find(atom);
|
| 162 |
+
bond_index_it != bond_index_by_atom.end()) {
|
| 163 |
+
for (std::size_t bond_index : bond_index_it->second) {
|
| 164 |
+
if (bond_index < 0 || bond_index >= bond_atom_indices.size()) {
|
| 165 |
+
return absl::OutOfRangeError(
|
| 166 |
+
absl::StrCat("Bond index out of range: ", bond_index));
|
| 167 |
+
}
|
| 168 |
+
bond_atom_indices[bond_index] = atom_index;
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
return absl::OkStatus();
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
// Checks that the CifDict has all of the columns in the column spec.
|
| 175 |
+
bool HasAllColumns(const CifDict& mmcif, const ColumnSpec& columns) {
|
| 176 |
+
return mmcif.Contains(columns.chain_id_col) &&
|
| 177 |
+
mmcif.Contains(columns.res_id_1_col) &&
|
| 178 |
+
mmcif.Contains(columns.res_id_2_col) &&
|
| 179 |
+
mmcif.Contains(columns.atom_name_col) &&
|
| 180 |
+
(!columns.alt_id_col.has_value() ||
|
| 181 |
+
mmcif.Contains(*columns.alt_id_col));
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
// Fully specified ptnr1 atom.
|
| 185 |
+
constexpr ColumnSpec kStructConnPtnr1ColumnsFull{
|
| 186 |
+
.chain_id_col = "_struct_conn.ptnr1_label_asym_id",
|
| 187 |
+
.res_id_1_col = "_struct_conn.ptnr1_auth_seq_id",
|
| 188 |
+
.res_id_2_col = "_struct_conn.pdbx_ptnr1_PDB_ins_code",
|
| 189 |
+
.atom_name_col = "_struct_conn.ptnr1_label_atom_id",
|
| 190 |
+
.alt_id_col = "_struct_conn.pdbx_ptnr1_label_alt_id",
|
| 191 |
+
};
|
| 192 |
+
|
| 193 |
+
// Fully specified ptnr2 atom.
|
| 194 |
+
constexpr ColumnSpec kStructConnPtnr2ColumnsFull{
|
| 195 |
+
.chain_id_col = "_struct_conn.ptnr2_label_asym_id",
|
| 196 |
+
.res_id_1_col = "_struct_conn.ptnr2_auth_seq_id",
|
| 197 |
+
.res_id_2_col = "_struct_conn.pdbx_ptnr2_PDB_ins_code",
|
| 198 |
+
.atom_name_col = "_struct_conn.ptnr2_label_atom_id",
|
| 199 |
+
.alt_id_col = "_struct_conn.pdbx_ptnr2_label_alt_id",
|
| 200 |
+
};
|
| 201 |
+
|
| 202 |
+
// Columns used by OpenMM for ptnr1 atoms.
|
| 203 |
+
constexpr ColumnSpec kStructConnPtnr1OpenMM{
|
| 204 |
+
.chain_id_col = "_struct_conn.ptnr1_label_asym_id",
|
| 205 |
+
.res_id_1_col = "_struct_conn.ptnr1_label_seq_id",
|
| 206 |
+
.res_id_2_col = "_struct_conn.ptnr1_label_comp_id",
|
| 207 |
+
.atom_name_col = "_struct_conn.ptnr1_label_atom_id",
|
| 208 |
+
.alt_id_col = std::nullopt,
|
| 209 |
+
};
|
| 210 |
+
|
| 211 |
+
// Columns used by OpenMM for ptnr2 atoms.
|
| 212 |
+
constexpr ColumnSpec kStructConnPtnr2OpenMM{
|
| 213 |
+
.chain_id_col = "_struct_conn.ptnr2_label_asym_id",
|
| 214 |
+
.res_id_1_col = "_struct_conn.ptnr2_label_seq_id",
|
| 215 |
+
.res_id_2_col = "_struct_conn.ptnr2_label_comp_id",
|
| 216 |
+
.atom_name_col = "_struct_conn.ptnr2_label_atom_id",
|
| 217 |
+
.alt_id_col = std::nullopt,
|
| 218 |
+
};
|
| 219 |
+
|
| 220 |
+
// Fully specified atom sites.
|
| 221 |
+
constexpr ColumnSpec kAtomSiteColumnsFull{
|
| 222 |
+
.chain_id_col = "_atom_site.label_asym_id",
|
| 223 |
+
.res_id_1_col = "_atom_site.auth_seq_id",
|
| 224 |
+
.res_id_2_col = "_atom_site.pdbx_PDB_ins_code",
|
| 225 |
+
.atom_name_col = "_atom_site.label_atom_id",
|
| 226 |
+
.alt_id_col = "_atom_site.label_alt_id",
|
| 227 |
+
};
|
| 228 |
+
|
| 229 |
+
// Atom site columns used to match OpenMM _struct_conn tables.
|
| 230 |
+
constexpr ColumnSpec kAtomSiteColumnsOpenMM{
|
| 231 |
+
.chain_id_col = "_atom_site.label_asym_id",
|
| 232 |
+
.res_id_1_col = "_atom_site.label_seq_id",
|
| 233 |
+
.res_id_2_col = "_atom_site.label_comp_id",
|
| 234 |
+
.atom_name_col = "_atom_site.label_atom_id",
|
| 235 |
+
.alt_id_col = "_atom_site.label_alt_id",
|
| 236 |
+
};
|
| 237 |
+
|
| 238 |
+
} // namespace
|
| 239 |
+
|
| 240 |
+
absl::StatusOr<std::pair<BondAtomIndices, BondAtomIndices>> GetBondAtomIndices(
|
| 241 |
+
const CifDict& mmcif, absl::string_view model_id) {
|
| 242 |
+
ColumnSpec ptnr1_columns, ptnr2_columns, atom_site_columns;
|
| 243 |
+
|
| 244 |
+
if (HasAllColumns(mmcif, kStructConnPtnr1ColumnsFull) &&
|
| 245 |
+
HasAllColumns(mmcif, kStructConnPtnr2ColumnsFull)) {
|
| 246 |
+
ptnr1_columns = kStructConnPtnr1ColumnsFull;
|
| 247 |
+
ptnr2_columns = kStructConnPtnr2ColumnsFull;
|
| 248 |
+
atom_site_columns = kAtomSiteColumnsFull;
|
| 249 |
+
} else {
|
| 250 |
+
ptnr1_columns = kStructConnPtnr1OpenMM;
|
| 251 |
+
ptnr2_columns = kStructConnPtnr2OpenMM;
|
| 252 |
+
atom_site_columns = kAtomSiteColumnsOpenMM;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
absl::StatusOr<AtomColumns> ptnr1_atoms =
|
| 256 |
+
AtomColumns::Create(mmcif, ptnr1_columns);
|
| 257 |
+
if (!ptnr1_atoms.ok()) {
|
| 258 |
+
return ptnr1_atoms.status();
|
| 259 |
+
}
|
| 260 |
+
absl::StatusOr<AtomColumns> ptnr2_atoms =
|
| 261 |
+
AtomColumns::Create(mmcif, ptnr2_columns);
|
| 262 |
+
if (!ptnr2_atoms.ok()) {
|
| 263 |
+
return ptnr2_atoms.status();
|
| 264 |
+
}
|
| 265 |
+
StringArrayRef struct_conn_id = mmcif["_struct_conn.id"];
|
| 266 |
+
if (!AreSameSize(struct_conn_id, *ptnr1_atoms, *ptnr2_atoms)) {
|
| 267 |
+
return absl::InvalidArgumentError(absl::StrCat(
|
| 268 |
+
"Invalid '_struct_conn.' loop. ", //
|
| 269 |
+
"len(id) = ", struct_conn_id.size(), ", ", //
|
| 270 |
+
"len(ptnr1_atoms) = ", ptnr1_atoms->size(), ", ", //
|
| 271 |
+
"len(ptnr2_atoms) = ", ptnr2_atoms->size(), "." //
|
| 272 |
+
));
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
absl::StatusOr<AtomColumns> atoms =
|
| 276 |
+
AtomColumns::Create(mmcif, atom_site_columns);
|
| 277 |
+
if (!atoms.ok()) {
|
| 278 |
+
return atoms.status();
|
| 279 |
+
}
|
| 280 |
+
StringArrayRef atom_site_id = mmcif["_atom_site.id"];
|
| 281 |
+
StringArrayRef atom_site_model_id = mmcif["_atom_site.pdbx_PDB_model_num"];
|
| 282 |
+
if (!AreSameSize(atom_site_id, atom_site_model_id, *atoms)) {
|
| 283 |
+
return absl::InvalidArgumentError(absl::StrCat(
|
| 284 |
+
"Invalid '_atom_site.' loop. ", //
|
| 285 |
+
"len(id)= ", atom_site_id.size(), ", ", //
|
| 286 |
+
"len(pdbx_PDB_model_num)= ", atom_site_model_id.size(), ", ", //
|
| 287 |
+
"len(atoms)= ", atoms->size(), ".")); //
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
// Build maps from atom ID tuples to the rows in _struct_conn where that
|
| 291 |
+
// atom appears (NB could be multiple).
|
| 292 |
+
const std::size_t struct_conn_size = struct_conn_id.size();
|
| 293 |
+
BondIndexByAtom ptnr1_rows_by_atom(struct_conn_size);
|
| 294 |
+
BondIndexByAtom ptnr2_rows_by_atom(struct_conn_size);
|
| 295 |
+
for (std::size_t i = 0; i < struct_conn_size; ++i) {
|
| 296 |
+
ptnr1_rows_by_atom[ptnr1_atoms->GetAtom(i)].push_back(i);
|
| 297 |
+
ptnr2_rows_by_atom[ptnr2_atoms->GetAtom(i)].push_back(i);
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
// Allocate two output arrays with one element per row in struct_conn, where
|
| 301 |
+
// each element will be the index of that atom in the atom_site table.
|
| 302 |
+
// Fill the arrays with atom_site_size, which is an invalid value, so that
|
| 303 |
+
// we can check at the end that each atom has been found.
|
| 304 |
+
const std::size_t atom_site_size = atom_site_id.size();
|
| 305 |
+
BondAtomIndices ptnr1_atom_indices(struct_conn_size, atom_site_size);
|
| 306 |
+
BondAtomIndices ptnr2_atom_indices(struct_conn_size, atom_site_size);
|
| 307 |
+
|
| 308 |
+
bool model_id_ecountered = false;
|
| 309 |
+
absl::flat_hash_set<absl::string_view> seen_alt_ids;
|
| 310 |
+
for (std::size_t atom_i = 0; atom_i < atom_site_size; ++atom_i) {
|
| 311 |
+
if (atom_site_model_id[atom_i] != model_id) {
|
| 312 |
+
if (!model_id_ecountered) {
|
| 313 |
+
continue;
|
| 314 |
+
} else {
|
| 315 |
+
// Models are contiguous so once we see a different model ID after
|
| 316 |
+
// encountering our model ID then we can exit early.
|
| 317 |
+
break;
|
| 318 |
+
}
|
| 319 |
+
} else {
|
| 320 |
+
model_id_ecountered = true;
|
| 321 |
+
}
|
| 322 |
+
AtomId atom = atoms->GetAtom(atom_i);
|
| 323 |
+
seen_alt_ids.insert(atom.alt_id);
|
| 324 |
+
|
| 325 |
+
if (auto fill_in_bonds_status1 = FillInBondsForAtom(
|
| 326 |
+
ptnr1_rows_by_atom, atom, atom_i, ptnr1_atom_indices);
|
| 327 |
+
!fill_in_bonds_status1.ok()) {
|
| 328 |
+
return fill_in_bonds_status1;
|
| 329 |
+
}
|
| 330 |
+
if (auto fill_in_bonds_status2 = FillInBondsForAtom(
|
| 331 |
+
ptnr2_rows_by_atom, atom, atom_i, ptnr2_atom_indices);
|
| 332 |
+
!fill_in_bonds_status2.ok()) {
|
| 333 |
+
return fill_in_bonds_status2;
|
| 334 |
+
}
|
| 335 |
+
}
|
| 336 |
+
// The seen_alt_ids check is a workaround for a known PDB issue: some mmCIFs
|
| 337 |
+
// (2evw, 2g0v, 2g0x, 2g0z, 2g10, 2g11, 2g12, 2g14, 2grz, 2ntw as of 2024)
|
| 338 |
+
// have multiple models and they set different whole-chain altloc in each
|
| 339 |
+
// model. The bond table however doesn't distinguish between models, so there
|
| 340 |
+
// are bonds that are valid only for some models. E.g. 2grz has model 1 with
|
| 341 |
+
// chain A with altloc A, and model 2 with chain A with altloc B. The bonds
|
| 342 |
+
// table lists a bond for each of these.
|
| 343 |
+
|
| 344 |
+
// Check that a ptnr1 atom was found for every bond.
|
| 345 |
+
if (auto row_it = absl::c_find(ptnr1_atom_indices, atom_site_size);
|
| 346 |
+
row_it != ptnr1_atom_indices.end()) {
|
| 347 |
+
if (seen_alt_ids.size() > 1 || seen_alt_ids.contains(".") ||
|
| 348 |
+
seen_alt_ids.contains("?")) {
|
| 349 |
+
std::size_t i = std::distance(ptnr1_atom_indices.begin(), row_it);
|
| 350 |
+
return absl::InvalidArgumentError(
|
| 351 |
+
absl::StrCat("Error parsing \"", mmcif.GetDataName(), "\". ",
|
| 352 |
+
"Cannot find atom for bond ID ", struct_conn_id[i], ": ",
|
| 353 |
+
ptnr1_atoms->GetAtomString(i)));
|
| 354 |
+
}
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
// Check that a ptnr2 atom was found for every bond.
|
| 358 |
+
if (auto row_it = absl::c_find(ptnr2_atom_indices, atom_site_size);
|
| 359 |
+
row_it != ptnr2_atom_indices.end()) {
|
| 360 |
+
if (seen_alt_ids.size() > 1 || seen_alt_ids.contains(".") ||
|
| 361 |
+
seen_alt_ids.contains("?")) {
|
| 362 |
+
std::size_t i = std::distance(ptnr2_atom_indices.begin(), row_it);
|
| 363 |
+
return absl::InvalidArgumentError(
|
| 364 |
+
absl::StrCat("Error parsing \"", mmcif.GetDataName(), "\". ",
|
| 365 |
+
"Cannot find atom for bond ID ", struct_conn_id[i], ": ",
|
| 366 |
+
ptnr2_atoms->GetAtomString(i)));
|
| 367 |
+
}
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
if (!model_id_ecountered) {
|
| 371 |
+
return absl::InvalidArgumentError(absl::StrCat(
|
| 372 |
+
"Error parsing \"", mmcif.GetDataName(), "\". model_id \"", model_id,
|
| 373 |
+
"\" not found in _atom_site.pdbx_PDB_model_num."));
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
return std::make_pair(std::move(ptnr1_atom_indices),
|
| 377 |
+
std::move(ptnr2_atom_indices));
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
} // namespace alphafold3
|
flax_model/alphafold3/structure/cpp/mmcif_struct_conn_pybind.cc
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
//
|
| 3 |
+
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
//
|
| 6 |
+
// To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
// out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
// if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
#include <string>
|
| 12 |
+
|
| 13 |
+
#include "absl/strings/string_view.h"
|
| 14 |
+
#include "alphafold3/parsers/cpp/cif_dict_lib.h"
|
| 15 |
+
#include "alphafold3/structure/cpp/mmcif_struct_conn.h"
|
| 16 |
+
#include "pybind11/gil.h"
|
| 17 |
+
#include "pybind11/pybind11.h"
|
| 18 |
+
#include "pybind11/pytypes.h"
|
| 19 |
+
#include "pybind11/stl.h"
|
| 20 |
+
|
| 21 |
+
namespace alphafold3 {
|
| 22 |
+
|
| 23 |
+
namespace py = pybind11;
|
| 24 |
+
|
| 25 |
+
constexpr char kGetBondAtomIndices[] = R"(
|
| 26 |
+
Extracts the indices of the atoms that participate in bonds.
|
| 27 |
+
|
| 28 |
+
This function has a workaround for a known PDB issue: some mmCIFs have
|
| 29 |
+
(2evw, 2g0v, 2g0x, 2g0z, 2g10, 2g11, 2g12, 2g14, 2grz, 2ntw as of 2024)
|
| 30 |
+
multiple models and they set different whole-chain altloc in each model.
|
| 31 |
+
The bond table however doesn't distinguish between models, so there are
|
| 32 |
+
bonds that are valid only for some models. E.g. 2grz has model 1 with
|
| 33 |
+
chain A with altloc A, and model 2 with chain A with altloc B. The bonds
|
| 34 |
+
table lists a bond for each of these. This case is rather rare (10 cases
|
| 35 |
+
in PDB as of 2024). For the offending bonds, the returned atom index is
|
| 36 |
+
set to the size of the atom_site table, i.e. it is an invalid index.
|
| 37 |
+
|
| 38 |
+
Args:
|
| 39 |
+
mmcif: The mmCIF object to process.
|
| 40 |
+
model_id: The ID of the model that the returned atoms will belong to. This
|
| 41 |
+
should be a value in the mmCIF's _atom_site.pdbx_PDB_model_num column.
|
| 42 |
+
|
| 43 |
+
Returns:
|
| 44 |
+
Two lists of atom indices, `from_atoms` and `to_atoms`, each one having
|
| 45 |
+
length num_bonds (as defined by _struct_conn, the bonds table). The bond
|
| 46 |
+
i, defined by the i'th row in _struct_conn, is a bond from atom at index
|
| 47 |
+
from_atoms[i], to the atom at index to_atoms[i]. The indices are simple
|
| 48 |
+
0-based indexes into the columns of the _atom_site table in the input
|
| 49 |
+
mmCIF, and do not necessarily correspond to the values in _atom_site.id,
|
| 50 |
+
or any other column.
|
| 51 |
+
)";
|
| 52 |
+
|
| 53 |
+
void RegisterModuleMmcifStructConn(pybind11::module m) {
|
| 54 |
+
m.def(
|
| 55 |
+
"get_bond_atom_indices",
|
| 56 |
+
[](const CifDict& mmcif, absl::string_view model_id) {
|
| 57 |
+
auto result = GetBondAtomIndices(mmcif, model_id);
|
| 58 |
+
if (result.ok()) {
|
| 59 |
+
return *result;
|
| 60 |
+
}
|
| 61 |
+
throw py::value_error(std::string(result.status().message()));
|
| 62 |
+
},
|
| 63 |
+
py::arg("mmcif_dict"), py::arg("model_id"),
|
| 64 |
+
py::doc(kGetBondAtomIndices + 1),
|
| 65 |
+
py::call_guard<py::gil_scoped_release>());
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
} // namespace alphafold3
|
flax_model/alphafold3/structure/cpp/mmcif_struct_conn_pybind.h
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_STRUCT_CONN_PYBIND_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_STRUCT_CONN_PYBIND_H_
|
| 15 |
+
|
| 16 |
+
#include "pybind11/pybind11.h"
|
| 17 |
+
|
| 18 |
+
namespace alphafold3 {
|
| 19 |
+
|
| 20 |
+
void RegisterModuleMmcifStructConn(pybind11::module m);
|
| 21 |
+
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_STRUCT_CONN_PYBIND_H_
|
flax_model/alphafold3/structure/cpp/mmcif_utils.pyi
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
from collections.abc import Sequence
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
from flax_model.alphafold3.cpp import cif_dict
|
| 8 |
+
from flax_model.alphafold3.structure.python import mmcif_layout
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def filter(
|
| 12 |
+
mmcif: cif_dict.CifDict,
|
| 13 |
+
include_nucleotides: bool,
|
| 14 |
+
include_ligands: bool = ...,
|
| 15 |
+
include_water: bool = ...,
|
| 16 |
+
include_other: bool = ...,
|
| 17 |
+
model_id: str = ...,
|
| 18 |
+
) -> tuple[np.ndarray[int], mmcif_layout.MmcifLayout]: ...
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def fix_residues(
|
| 22 |
+
layout: mmcif_layout.MmcifLayout,
|
| 23 |
+
comp_id: Sequence[str],
|
| 24 |
+
atom_id: Sequence[str],
|
| 25 |
+
atom_x: Sequence[float],
|
| 26 |
+
atom_y: Sequence[float],
|
| 27 |
+
atom_z: Sequence[float],
|
| 28 |
+
fix_arg: bool = ...,
|
| 29 |
+
) -> None: ...
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def read_layout(
|
| 33 |
+
mmcif: cif_dict.CifDict, model_id: str = ...
|
| 34 |
+
) -> mmcif_layout.MmcifLayout: ...
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def selected_ligand_residue_mask(
|
| 38 |
+
layout: mmcif_layout.MmcifLayout,
|
| 39 |
+
atom_site_label_asym_ids: list[str],
|
| 40 |
+
atom_site_label_seq_ids: list[str],
|
| 41 |
+
atom_site_auth_seq_ids: list[str],
|
| 42 |
+
atom_site_label_comp_ids: list[str],
|
| 43 |
+
atom_site_pdbx_pdb_ins_codes: list[str],
|
| 44 |
+
nonpoly_asym_ids: list[str],
|
| 45 |
+
nonpoly_auth_seq_ids: list[str],
|
| 46 |
+
nonpoly_pdb_ins_codes: list[str],
|
| 47 |
+
nonpoly_mon_ids: list[str],
|
| 48 |
+
branch_asym_ids: list[str],
|
| 49 |
+
branch_auth_seq_ids: list[str],
|
| 50 |
+
branch_pdb_ins_codes: list[str],
|
| 51 |
+
branch_mon_ids: list[str],
|
| 52 |
+
) -> tuple[list[bool], list[bool]]: ...
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def selected_polymer_residue_mask(
|
| 56 |
+
layout: mmcif_layout.MmcifLayout,
|
| 57 |
+
atom_site_label_asym_ids: list[str],
|
| 58 |
+
atom_site_label_seq_ids: list[str],
|
| 59 |
+
atom_site_label_comp_ids: list[str],
|
| 60 |
+
poly_seq_asym_ids: list[str],
|
| 61 |
+
poly_seq_seq_ids: list[str],
|
| 62 |
+
poly_seq_mon_ids: list[str],
|
| 63 |
+
) -> list[bool]: ...
|
flax_model/alphafold3/structure/cpp/mmcif_utils_pybind.cc
ADDED
|
@@ -0,0 +1,787 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
//
|
| 3 |
+
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
//
|
| 6 |
+
// To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
// out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
// if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
#include <Python.h>
|
| 12 |
+
|
| 13 |
+
#include <algorithm>
|
| 14 |
+
#include <cstddef>
|
| 15 |
+
#include <cstdint>
|
| 16 |
+
#include <iterator>
|
| 17 |
+
#include <memory>
|
| 18 |
+
#include <new>
|
| 19 |
+
#include <optional>
|
| 20 |
+
#include <string>
|
| 21 |
+
#include <tuple>
|
| 22 |
+
#include <utility>
|
| 23 |
+
#include <vector>
|
| 24 |
+
|
| 25 |
+
#include "numpy/ndarrayobject.h"
|
| 26 |
+
#include "numpy/ndarraytypes.h"
|
| 27 |
+
#include "numpy/npy_common.h"
|
| 28 |
+
#include "absl/container/flat_hash_map.h"
|
| 29 |
+
#include "absl/container/flat_hash_set.h"
|
| 30 |
+
#include "absl/memory/memory.h"
|
| 31 |
+
#include "absl/strings/str_cat.h"
|
| 32 |
+
#include "absl/strings/string_view.h"
|
| 33 |
+
#include "absl/types/span.h"
|
| 34 |
+
#include "alphafold3/parsers/cpp/cif_dict_lib.h"
|
| 35 |
+
#include "alphafold3/structure/cpp/mmcif_altlocs.h"
|
| 36 |
+
#include "alphafold3/structure/cpp/mmcif_layout.h"
|
| 37 |
+
#include "pybind11/cast.h"
|
| 38 |
+
#include "pybind11/gil.h"
|
| 39 |
+
#include "pybind11/numpy.h"
|
| 40 |
+
#include "pybind11/pybind11.h"
|
| 41 |
+
#include "pybind11/pytypes.h"
|
| 42 |
+
#include "pybind11/stl.h"
|
| 43 |
+
#include "pybind11_abseil/absl_casters.h"
|
| 44 |
+
|
| 45 |
+
namespace alphafold3 {
|
| 46 |
+
namespace {
|
| 47 |
+
namespace py = pybind11;
|
| 48 |
+
|
| 49 |
+
struct PyObjectDeleter {
|
| 50 |
+
inline void operator()(PyObject* obj) const { Py_CLEAR(obj); }
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
using ScopedPyObject = std::unique_ptr<PyObject, PyObjectDeleter>;
|
| 54 |
+
|
| 55 |
+
using StringArrayRef = absl::Span<const std::string>;
|
| 56 |
+
using Indexer = absl::flat_hash_map<absl::string_view, std::size_t>;
|
| 57 |
+
|
| 58 |
+
// Returns the reverse look-up map of name to index.
|
| 59 |
+
Indexer MakeIndex(StringArrayRef col) {
|
| 60 |
+
Indexer index;
|
| 61 |
+
index.reserve(col.size());
|
| 62 |
+
for (std::size_t i = 0; i < col.size(); ++i) {
|
| 63 |
+
index[col[i]] = i;
|
| 64 |
+
}
|
| 65 |
+
return index;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
// Returns whether each container is the same size.
|
| 69 |
+
template <typename C, typename... Cs>
|
| 70 |
+
bool AreSameSize(C c, const Cs&... cs) {
|
| 71 |
+
return ((c.size() == cs.size()) && ...);
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
// Stores references to columns in `_atom_site` ensuring they all exist and
|
| 75 |
+
// are the same size.
|
| 76 |
+
struct AtomSiteLoop {
|
| 77 |
+
explicit AtomSiteLoop(const CifDict& cif_dict)
|
| 78 |
+
: id(cif_dict["_atom_site.id"]),
|
| 79 |
+
model_id(cif_dict["_atom_site.pdbx_PDB_model_num"]),
|
| 80 |
+
chain_id(cif_dict["_atom_site.label_asym_id"]),
|
| 81 |
+
seq_id(cif_dict["_atom_site.label_seq_id"]),
|
| 82 |
+
|
| 83 |
+
comp_id(cif_dict["_atom_site.label_comp_id"]),
|
| 84 |
+
atom_id(cif_dict["_atom_site.label_atom_id"]),
|
| 85 |
+
|
| 86 |
+
alt_id(cif_dict["_atom_site.label_alt_id"]),
|
| 87 |
+
occupancy(cif_dict["_atom_site.occupancy"])
|
| 88 |
+
|
| 89 |
+
{
|
| 90 |
+
if (!AreSameSize(id, model_id, chain_id, seq_id, comp_id, atom_id, alt_id,
|
| 91 |
+
occupancy)) {
|
| 92 |
+
throw py::value_error(
|
| 93 |
+
absl::StrCat("Invalid '_atom_site.' loop. ", //
|
| 94 |
+
"len(id)=", id.size(), ", ", //
|
| 95 |
+
"len(pdbx_PDB_model_num)=", model_id.size(), ", ", //
|
| 96 |
+
"len(label_asym_id)=", chain_id.size(), ", ", //
|
| 97 |
+
"len(label_seq_id)=", seq_id.size(), ", ", //
|
| 98 |
+
"len(label_comp_id)=", comp_id.size(), ", ", //
|
| 99 |
+
"len(atom_id)=", atom_id.size(), ", ", //
|
| 100 |
+
"len(label_alt_id)=", alt_id.size(), ", ", //
|
| 101 |
+
"len(occupancy)=", occupancy.size()));
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
StringArrayRef id;
|
| 105 |
+
StringArrayRef model_id;
|
| 106 |
+
StringArrayRef chain_id;
|
| 107 |
+
StringArrayRef seq_id;
|
| 108 |
+
StringArrayRef comp_id;
|
| 109 |
+
StringArrayRef atom_id;
|
| 110 |
+
StringArrayRef alt_id;
|
| 111 |
+
StringArrayRef occupancy;
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
+
// Stores references to columns in `_entity` ensuring they all exist and are the
|
| 115 |
+
// same size.
|
| 116 |
+
struct EntityLoop {
|
| 117 |
+
explicit EntityLoop(const CifDict& cif_dict)
|
| 118 |
+
: id(cif_dict["_entity.id"]), type(cif_dict["_entity.type"]) {
|
| 119 |
+
if (!AreSameSize(id, type)) {
|
| 120 |
+
throw py::value_error(absl::StrCat("Invalid '_entity.' loop. ", //
|
| 121 |
+
"len(id)=", id.size(), ", ", //
|
| 122 |
+
"len(type)=", type.size()));
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
StringArrayRef id;
|
| 126 |
+
StringArrayRef type;
|
| 127 |
+
};
|
| 128 |
+
|
| 129 |
+
// Stores references to columns in `_entity_poly` ensuring they all exist and
|
| 130 |
+
// are the same size.
|
| 131 |
+
struct EntityPolyLoop {
|
| 132 |
+
explicit EntityPolyLoop(const CifDict& cif_dict)
|
| 133 |
+
: entity_id(cif_dict["_entity_poly.entity_id"]),
|
| 134 |
+
type(cif_dict["_entity_poly.type"]) {
|
| 135 |
+
if (!AreSameSize(entity_id, type)) {
|
| 136 |
+
throw py::value_error(absl::StrCat("Invalid '_entity_poly.' loop. ", //
|
| 137 |
+
"len(entity_id)=", entity_id.size(),
|
| 138 |
+
", ", //
|
| 139 |
+
"len(type)=", type.size()));
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
StringArrayRef entity_id;
|
| 143 |
+
StringArrayRef type;
|
| 144 |
+
};
|
| 145 |
+
|
| 146 |
+
// Returns a set of entity names removing ones not included by the flags
|
| 147 |
+
// specified.
|
| 148 |
+
absl::flat_hash_set<absl::string_view> SelectChains(const CifDict& mmcif,
|
| 149 |
+
bool include_nucleotides,
|
| 150 |
+
bool include_ligands,
|
| 151 |
+
bool include_water,
|
| 152 |
+
bool include_other) {
|
| 153 |
+
EntityLoop entity_loop(mmcif);
|
| 154 |
+
EntityPolyLoop entity_poly(mmcif);
|
| 155 |
+
absl::flat_hash_set<absl::string_view> permitted_polymers{"polypeptide(L)"};
|
| 156 |
+
absl::flat_hash_set<absl::string_view> forbidden_polymers;
|
| 157 |
+
for (absl::string_view type :
|
| 158 |
+
{"polydeoxyribonucleotide", "polyribonucleotide",
|
| 159 |
+
"polydeoxyribonucleotide/polyribonucleotide hybrid"}) {
|
| 160 |
+
if (include_nucleotides) {
|
| 161 |
+
permitted_polymers.emplace(type);
|
| 162 |
+
} else {
|
| 163 |
+
forbidden_polymers.emplace(type);
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
absl::flat_hash_set<absl::string_view> permitted_nonpoly_entity_types;
|
| 168 |
+
absl::flat_hash_set<absl::string_view> forbidden_nonpoly_entity_types;
|
| 169 |
+
for (absl::string_view type : {"non-polymer", "branched"}) {
|
| 170 |
+
if (include_ligands) {
|
| 171 |
+
permitted_nonpoly_entity_types.emplace(type);
|
| 172 |
+
} else {
|
| 173 |
+
forbidden_nonpoly_entity_types.emplace(type);
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
absl::string_view water_type = "water";
|
| 177 |
+
if (include_water) {
|
| 178 |
+
permitted_nonpoly_entity_types.emplace(water_type);
|
| 179 |
+
} else {
|
| 180 |
+
forbidden_nonpoly_entity_types.emplace(water_type);
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
StringArrayRef chain_ids = mmcif["_struct_asym.id"];
|
| 184 |
+
StringArrayRef entity_ids = mmcif["_struct_asym.entity_id"];
|
| 185 |
+
Indexer chain_index = MakeIndex(chain_ids);
|
| 186 |
+
Indexer entity_poly_index = MakeIndex(entity_poly.entity_id);
|
| 187 |
+
Indexer entity_id_to_index = MakeIndex(entity_loop.id);
|
| 188 |
+
|
| 189 |
+
absl::flat_hash_set<absl::string_view> keep_chain_id;
|
| 190 |
+
for (std::size_t i = 0; i < chain_ids.size(); ++i) {
|
| 191 |
+
absl::string_view chain_id = chain_ids[i];
|
| 192 |
+
absl::string_view entity_id = entity_ids[i];
|
| 193 |
+
if (entity_id_to_index.empty() ||
|
| 194 |
+
entity_loop.type[entity_id_to_index[entity_id]] == "polymer") {
|
| 195 |
+
if (auto it = entity_poly_index.find(entity_id);
|
| 196 |
+
it != entity_poly_index.end()) {
|
| 197 |
+
absl::string_view poly_type = entity_poly.type[it->second];
|
| 198 |
+
if (include_other) {
|
| 199 |
+
if (!forbidden_polymers.contains(poly_type)) {
|
| 200 |
+
keep_chain_id.insert(chain_id);
|
| 201 |
+
}
|
| 202 |
+
} else {
|
| 203 |
+
if (permitted_polymers.contains(poly_type)) {
|
| 204 |
+
keep_chain_id.insert(chain_id);
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
} else {
|
| 209 |
+
absl::string_view entity_type =
|
| 210 |
+
entity_loop.type[entity_id_to_index[entity_id]];
|
| 211 |
+
if (include_other) {
|
| 212 |
+
if (!forbidden_nonpoly_entity_types.contains(entity_type)) {
|
| 213 |
+
keep_chain_id.insert(chain_id);
|
| 214 |
+
continue;
|
| 215 |
+
}
|
| 216 |
+
} else {
|
| 217 |
+
if (permitted_nonpoly_entity_types.contains(entity_type)) {
|
| 218 |
+
keep_chain_id.insert(chain_id);
|
| 219 |
+
continue;
|
| 220 |
+
}
|
| 221 |
+
}
|
| 222 |
+
}
|
| 223 |
+
}
|
| 224 |
+
return keep_chain_id;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
class ProcessResidue {
|
| 228 |
+
public:
|
| 229 |
+
explicit ProcessResidue(const char* residue)
|
| 230 |
+
: residue_(PyUnicode_InternFromString(residue)) {}
|
| 231 |
+
bool IsResidue(PyObject* residue) {
|
| 232 |
+
return ArePyObjectsEqual(residue_.get(), residue);
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
static bool ArePyObjectsEqual(PyObject* lhs, PyObject* rhs) {
|
| 236 |
+
switch (PyObject_RichCompareBool(lhs, rhs, Py_EQ)) {
|
| 237 |
+
case -1:
|
| 238 |
+
PyErr_Clear();
|
| 239 |
+
return false;
|
| 240 |
+
case 0:
|
| 241 |
+
return false;
|
| 242 |
+
default:
|
| 243 |
+
return true;
|
| 244 |
+
}
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
private:
|
| 248 |
+
ScopedPyObject residue_;
|
| 249 |
+
};
|
| 250 |
+
|
| 251 |
+
struct Position3 {
|
| 252 |
+
float x;
|
| 253 |
+
float y;
|
| 254 |
+
float z;
|
| 255 |
+
};
|
| 256 |
+
|
| 257 |
+
float DistanceSquared(Position3 v1, Position3 v2) {
|
| 258 |
+
float dx = v1.x - v2.x;
|
| 259 |
+
float dy = v1.y - v2.y;
|
| 260 |
+
float dz = v1.z - v2.z;
|
| 261 |
+
return dx * dx + dy * dy + dz * dz;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
class FixArginine : public ProcessResidue {
|
| 265 |
+
public:
|
| 266 |
+
FixArginine()
|
| 267 |
+
: ProcessResidue("ARG"),
|
| 268 |
+
cd_(PyUnicode_InternFromString("CD")),
|
| 269 |
+
nh1_(PyUnicode_InternFromString("NH1")),
|
| 270 |
+
nh2_(PyUnicode_InternFromString("NH2")),
|
| 271 |
+
hh11_(PyUnicode_InternFromString("HH11")),
|
| 272 |
+
hh21_(PyUnicode_InternFromString("HH21")),
|
| 273 |
+
hh12_(PyUnicode_InternFromString("HH12")),
|
| 274 |
+
hh22_(PyUnicode_InternFromString("HH22")) {}
|
| 275 |
+
void Fix(absl::Span<PyObject*> atom_ids, absl::Span<const float> atom_x,
|
| 276 |
+
absl::Span<const float> atom_y, absl::Span<const float> atom_z) {
|
| 277 |
+
std::ptrdiff_t cd_index = -1;
|
| 278 |
+
std::ptrdiff_t nh1_index = -1;
|
| 279 |
+
std::ptrdiff_t nh2_index = -1;
|
| 280 |
+
std::ptrdiff_t hh11_index = -1;
|
| 281 |
+
std::ptrdiff_t hh21_index = -1;
|
| 282 |
+
std::ptrdiff_t hh12_index = -1;
|
| 283 |
+
std::ptrdiff_t hh22_index = -1;
|
| 284 |
+
for (std::ptrdiff_t index = 0; index < atom_ids.size(); ++index) {
|
| 285 |
+
PyObject* atom_id = atom_ids[index];
|
| 286 |
+
if (cd_index == -1 && ArePyObjectsEqual(atom_id, cd_.get())) {
|
| 287 |
+
cd_index = index;
|
| 288 |
+
} else if (nh1_index == -1 && ArePyObjectsEqual(atom_id, nh1_.get())) {
|
| 289 |
+
nh1_index = index;
|
| 290 |
+
} else if (nh2_index == -1 && ArePyObjectsEqual(atom_id, nh2_.get())) {
|
| 291 |
+
nh2_index = index;
|
| 292 |
+
} else if (hh11_index == -1 && ArePyObjectsEqual(atom_id, hh11_.get())) {
|
| 293 |
+
hh11_index = index;
|
| 294 |
+
} else if (hh21_index == -1 && ArePyObjectsEqual(atom_id, hh21_.get())) {
|
| 295 |
+
hh21_index = index;
|
| 296 |
+
} else if (hh12_index == -1 && ArePyObjectsEqual(atom_id, hh12_.get())) {
|
| 297 |
+
hh12_index = index;
|
| 298 |
+
} else if (hh22_index == -1 && ArePyObjectsEqual(atom_id, hh22_.get())) {
|
| 299 |
+
hh22_index = index;
|
| 300 |
+
}
|
| 301 |
+
}
|
| 302 |
+
if (cd_index < 0 || nh1_index < 0 || nh2_index < 0) {
|
| 303 |
+
return;
|
| 304 |
+
}
|
| 305 |
+
Position3 cd_pos(atom_x[cd_index], atom_y[cd_index], atom_z[cd_index]);
|
| 306 |
+
Position3 nh1_pos(atom_x[nh1_index], atom_y[nh1_index], atom_z[nh1_index]);
|
| 307 |
+
Position3 nh2_pos(atom_x[nh2_index], atom_y[nh2_index], atom_z[nh2_index]);
|
| 308 |
+
if (DistanceSquared(nh1_pos, cd_pos) <= DistanceSquared(nh2_pos, cd_pos)) {
|
| 309 |
+
return;
|
| 310 |
+
}
|
| 311 |
+
std::swap(atom_ids[nh1_index], atom_ids[nh2_index]);
|
| 312 |
+
if (hh11_index >= 0 && hh21_index >= 0) {
|
| 313 |
+
std::swap(atom_ids[hh11_index], atom_ids[hh21_index]);
|
| 314 |
+
} else if (hh11_index >= 0) {
|
| 315 |
+
Py_DECREF(atom_ids[hh11_index]);
|
| 316 |
+
Py_INCREF(hh21_.get());
|
| 317 |
+
atom_ids[hh11_index] = hh21_.get();
|
| 318 |
+
} else if (hh21_index >= 0) {
|
| 319 |
+
Py_DECREF(atom_ids[hh21_index]);
|
| 320 |
+
Py_INCREF(hh11_.get());
|
| 321 |
+
atom_ids[hh21_index] = hh11_.get();
|
| 322 |
+
}
|
| 323 |
+
if (hh12_index >= 0 && hh22_index >= 0) {
|
| 324 |
+
std::swap(atom_ids[hh12_index], atom_ids[hh22_index]);
|
| 325 |
+
} else if (hh12_index >= 0) {
|
| 326 |
+
Py_DECREF(atom_ids[hh12_index]);
|
| 327 |
+
Py_INCREF(hh22_.get());
|
| 328 |
+
atom_ids[hh12_index] = hh22_.get();
|
| 329 |
+
} else if (hh22_index >= 0) {
|
| 330 |
+
Py_DECREF(atom_ids[hh22_index]);
|
| 331 |
+
Py_INCREF(hh21_.get());
|
| 332 |
+
atom_ids[hh22_index] = hh21_.get();
|
| 333 |
+
}
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
private:
|
| 337 |
+
ScopedPyObject cd_;
|
| 338 |
+
ScopedPyObject nh1_;
|
| 339 |
+
ScopedPyObject nh2_;
|
| 340 |
+
ScopedPyObject hh11_;
|
| 341 |
+
ScopedPyObject hh21_;
|
| 342 |
+
ScopedPyObject hh12_;
|
| 343 |
+
ScopedPyObject hh22_;
|
| 344 |
+
};
|
| 345 |
+
|
| 346 |
+
// Returns the layout of the mmCIF `_atom_site` table.
|
| 347 |
+
inline MmcifLayout ReadMmcifLayout(const CifDict& mmcif,
|
| 348 |
+
absl::string_view model_id = "") {
|
| 349 |
+
py::gil_scoped_release release;
|
| 350 |
+
auto mmcif_layout = MmcifLayout::Create(mmcif, model_id);
|
| 351 |
+
if (mmcif_layout.ok()) {
|
| 352 |
+
return *mmcif_layout;
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
throw py::value_error(std::string(mmcif_layout.status().message()));
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
std::pair<py::object, MmcifLayout> MmcifFilter( //
|
| 359 |
+
const CifDict& mmcif, //
|
| 360 |
+
bool include_nucleotides, //
|
| 361 |
+
bool include_ligands, //
|
| 362 |
+
bool include_water, //
|
| 363 |
+
bool include_other, //
|
| 364 |
+
absl::string_view model_id) {
|
| 365 |
+
if (_import_array() < 0) {
|
| 366 |
+
throw py::import_error("Failed to import NumPy.");
|
| 367 |
+
}
|
| 368 |
+
auto layout = ReadMmcifLayout(mmcif, model_id);
|
| 369 |
+
std::unique_ptr<std::vector<std::uint64_t>> keep_indices;
|
| 370 |
+
size_t new_num_atoms;
|
| 371 |
+
|
| 372 |
+
{
|
| 373 |
+
py::gil_scoped_release release;
|
| 374 |
+
|
| 375 |
+
AtomSiteLoop atom_site(mmcif);
|
| 376 |
+
|
| 377 |
+
auto keep_chain_ids =
|
| 378 |
+
SelectChains(mmcif, include_nucleotides, include_ligands, include_water,
|
| 379 |
+
include_other);
|
| 380 |
+
|
| 381 |
+
std::vector<std::size_t> chain_indices;
|
| 382 |
+
chain_indices.reserve(keep_chain_ids.size());
|
| 383 |
+
for (std::size_t i = 0; i < layout.num_chains(); ++i) {
|
| 384 |
+
if (keep_chain_ids.contains(
|
| 385 |
+
atom_site.chain_id[layout.atom_site_from_chain_index(i)])) {
|
| 386 |
+
chain_indices.push_back(i);
|
| 387 |
+
}
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
keep_indices =
|
| 391 |
+
absl::WrapUnique(new std::vector<std::uint64_t>(ResolveMmcifAltLocs(
|
| 392 |
+
layout, atom_site.comp_id, atom_site.atom_id, atom_site.alt_id,
|
| 393 |
+
atom_site.occupancy, chain_indices)));
|
| 394 |
+
new_num_atoms = keep_indices->size();
|
| 395 |
+
|
| 396 |
+
if (layout.num_models() > 1) {
|
| 397 |
+
keep_indices->reserve(layout.num_models() * new_num_atoms);
|
| 398 |
+
std::uint64_t* start = &(*keep_indices->begin());
|
| 399 |
+
std::size_t num_atom = keep_indices->size();
|
| 400 |
+
// Copy first model indices into all model indices offsetting each copy.
|
| 401 |
+
for (std::size_t i = 1; i < layout.num_models(); ++i) {
|
| 402 |
+
std::size_t offset = i * layout.num_atoms();
|
| 403 |
+
std::transform(start, start + num_atom,
|
| 404 |
+
std::back_inserter(*keep_indices),
|
| 405 |
+
[offset](std::size_t v) { return v + offset; });
|
| 406 |
+
}
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
layout.Filter(*keep_indices);
|
| 411 |
+
|
| 412 |
+
npy_intp shape[] = {static_cast<npy_intp>(layout.num_models()),
|
| 413 |
+
static_cast<npy_intp>(new_num_atoms)};
|
| 414 |
+
PyObject* arr =
|
| 415 |
+
PyArray_SimpleNewFromData(2, shape, NPY_INT64, keep_indices->data());
|
| 416 |
+
// Create a capsule to hold the memory of the buffer so NumPy knows how to
|
| 417 |
+
// delete it when done with it.
|
| 418 |
+
PyObject* capsule = PyCapsule_New(
|
| 419 |
+
keep_indices.release(), nullptr, +[](PyObject* capsule_cleanup) {
|
| 420 |
+
void* memory = PyCapsule_GetPointer(capsule_cleanup, nullptr);
|
| 421 |
+
delete static_cast<std::vector<std::size_t>*>(memory);
|
| 422 |
+
});
|
| 423 |
+
PyArray_SetBaseObject(reinterpret_cast<PyArrayObject*>(arr), capsule);
|
| 424 |
+
|
| 425 |
+
return std::make_pair(py::reinterpret_steal<py::object>(arr),
|
| 426 |
+
std::move(layout));
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
void MmcifFixResidues( //
|
| 430 |
+
const MmcifLayout& layout, //
|
| 431 |
+
absl::Span<PyObject*> comp_id, //
|
| 432 |
+
absl::Span<PyObject*> atom_id, //
|
| 433 |
+
absl::Span<const float> atom_x, //
|
| 434 |
+
absl::Span<const float> atom_y, //
|
| 435 |
+
absl::Span<const float> atom_z, //
|
| 436 |
+
bool fix_arginine //
|
| 437 |
+
) {
|
| 438 |
+
std::optional<FixArginine> arginine;
|
| 439 |
+
std::size_t num_atoms = layout.num_atoms();
|
| 440 |
+
if (comp_id.size() != num_atoms || atom_id.size() != num_atoms ||
|
| 441 |
+
atom_x.size() != num_atoms || atom_y.size() != num_atoms ||
|
| 442 |
+
atom_z.size() != num_atoms) {
|
| 443 |
+
throw py::value_error(
|
| 444 |
+
absl::StrCat("Sizes must match. ", //
|
| 445 |
+
"num_atoms=", num_atoms, ", ", //
|
| 446 |
+
"len(comp_id)=", comp_id.size(), ", ", //
|
| 447 |
+
"len(atom_id)=", atom_id.size(), ", ", //
|
| 448 |
+
"len(atom_x)=", atom_x.size(), ", ", //
|
| 449 |
+
"len(atom_y)=", atom_y.size(), ", ", //
|
| 450 |
+
"len(atom_z)=", atom_z.size()));
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
if (fix_arginine) {
|
| 454 |
+
arginine.emplace();
|
| 455 |
+
}
|
| 456 |
+
if (!arginine.has_value()) {
|
| 457 |
+
return;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
for (std::size_t res_index = 0; res_index < layout.num_residues();
|
| 461 |
+
++res_index) {
|
| 462 |
+
auto [atom_start, atom_end] = layout.atom_range(res_index);
|
| 463 |
+
std::size_t atom_count = atom_end - atom_start;
|
| 464 |
+
PyObject* resname = comp_id[atom_start];
|
| 465 |
+
if (arginine.has_value() && arginine->IsResidue(resname)) {
|
| 466 |
+
arginine->Fix(atom_id.subspan(atom_start, atom_count),
|
| 467 |
+
atom_x.subspan(atom_start, atom_count),
|
| 468 |
+
atom_y.subspan(atom_start, atom_count),
|
| 469 |
+
atom_z.subspan(atom_start, atom_count));
|
| 470 |
+
}
|
| 471 |
+
}
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
std::vector<bool> SelectedPolymerResidueMask(
|
| 475 |
+
const MmcifLayout& layout,
|
| 476 |
+
const std::vector<absl::string_view>& atom_site_label_asym_ids, //
|
| 477 |
+
const std::vector<absl::string_view>& atom_site_label_seq_ids, //
|
| 478 |
+
const std::vector<absl::string_view>& atom_site_label_comp_ids, //
|
| 479 |
+
const std::vector<absl::string_view>& poly_seq_asym_ids, //
|
| 480 |
+
const std::vector<absl::string_view>& poly_seq_seq_ids, //
|
| 481 |
+
const std::vector<absl::string_view>& poly_seq_mon_ids //
|
| 482 |
+
) {
|
| 483 |
+
absl::flat_hash_map<std::pair<absl::string_view, absl::string_view>,
|
| 484 |
+
absl::string_view>
|
| 485 |
+
selected;
|
| 486 |
+
selected.reserve(layout.num_residues());
|
| 487 |
+
// layout.residues() is O(1) while layout.residue_starts() is O(num_res).
|
| 488 |
+
const std::vector<std::size_t>& residue_starts = layout.residue_starts();
|
| 489 |
+
for (int i = 0; i < layout.residues().size(); ++i) {
|
| 490 |
+
std::size_t res_start = residue_starts[i];
|
| 491 |
+
std::size_t res_end = layout.residues()[i];
|
| 492 |
+
if (res_start == res_end) {
|
| 493 |
+
continue; // Skip empty residues (containing no atoms).
|
| 494 |
+
}
|
| 495 |
+
|
| 496 |
+
absl::string_view label_seq_id = atom_site_label_seq_ids[i];
|
| 497 |
+
if (label_seq_id == ".") {
|
| 498 |
+
continue; // Skip non-polymers.
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
absl::string_view label_asym_id = atom_site_label_asym_ids[i];
|
| 502 |
+
absl::string_view label_comp_id = atom_site_label_comp_ids[i];
|
| 503 |
+
selected[std::make_pair(label_asym_id, label_seq_id)] = label_comp_id;
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
std::vector<bool> mask;
|
| 507 |
+
mask.reserve(poly_seq_mon_ids.size());
|
| 508 |
+
for (int i = 0; i < poly_seq_mon_ids.size(); ++i) {
|
| 509 |
+
absl::string_view poly_seq_asym_id = poly_seq_asym_ids[i];
|
| 510 |
+
absl::string_view poly_seq_seq_id = poly_seq_seq_ids[i];
|
| 511 |
+
absl::string_view poly_seq_mon_id = poly_seq_mon_ids[i];
|
| 512 |
+
|
| 513 |
+
auto it = selected.find(std::make_pair(poly_seq_asym_id, poly_seq_seq_id));
|
| 514 |
+
if (it != selected.end()) {
|
| 515 |
+
mask.push_back(it->second == poly_seq_mon_id);
|
| 516 |
+
} else {
|
| 517 |
+
mask.push_back(true); // Missing residues are not heterogeneous.
|
| 518 |
+
}
|
| 519 |
+
}
|
| 520 |
+
return mask;
|
| 521 |
+
}
|
| 522 |
+
|
| 523 |
+
std::pair<std::vector<bool>, std::vector<bool>> SelectedLigandResidueMask(
|
| 524 |
+
const MmcifLayout& layout, //
|
| 525 |
+
const std::vector<absl::string_view>& atom_site_label_asym_ids, //
|
| 526 |
+
const std::vector<absl::string_view>& atom_site_label_seq_ids, //
|
| 527 |
+
const std::vector<absl::string_view>& atom_site_auth_seq_ids, //
|
| 528 |
+
const std::vector<absl::string_view>& atom_site_label_comp_ids, //
|
| 529 |
+
const std::vector<absl::string_view>& atom_site_pdbx_pdb_ins_codes, //
|
| 530 |
+
const std::vector<absl::string_view>& nonpoly_asym_ids, //
|
| 531 |
+
const std::vector<absl::string_view>& nonpoly_auth_seq_ids, //
|
| 532 |
+
const std::vector<absl::string_view>& nonpoly_pdb_ins_codes, //
|
| 533 |
+
const std::vector<absl::string_view>& nonpoly_mon_ids, //
|
| 534 |
+
const std::vector<absl::string_view>& branch_asym_ids, //
|
| 535 |
+
const std::vector<absl::string_view>& branch_auth_seq_ids, //
|
| 536 |
+
const std::vector<absl::string_view>& branch_pdb_ins_codes, //
|
| 537 |
+
const std::vector<absl::string_view>& branch_mon_ids) {
|
| 538 |
+
absl::flat_hash_map<
|
| 539 |
+
std::tuple<absl::string_view, absl::string_view, absl::string_view>,
|
| 540 |
+
absl::string_view>
|
| 541 |
+
selected;
|
| 542 |
+
selected.reserve(layout.num_residues());
|
| 543 |
+
// layout.residues() is O(1) while layout.residue_starts() is O(num_res).
|
| 544 |
+
const std::vector<std::size_t>& residue_starts = layout.residue_starts();
|
| 545 |
+
for (int i = 0; i < layout.residues().size(); ++i) {
|
| 546 |
+
std::size_t res_start = residue_starts[i];
|
| 547 |
+
std::size_t res_end = layout.residues()[i];
|
| 548 |
+
if (res_start == res_end) {
|
| 549 |
+
continue; // Skip empty residues (containing no atoms).
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
absl::string_view label_seq_id = atom_site_label_seq_ids[i];
|
| 553 |
+
if (label_seq_id != ".") {
|
| 554 |
+
continue; // Skip polymers.
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
absl::string_view label_asym_id = atom_site_label_asym_ids[i];
|
| 558 |
+
absl::string_view auth_seq_id = atom_site_auth_seq_ids[i];
|
| 559 |
+
absl::string_view ins_code = atom_site_pdbx_pdb_ins_codes[i];
|
| 560 |
+
ins_code = ins_code == "?" ? "." : ins_code; // Remap unknown to unset.
|
| 561 |
+
absl::string_view label_comp_id = atom_site_label_comp_ids[i];
|
| 562 |
+
selected[std::make_tuple(label_asym_id, auth_seq_id, ins_code)] =
|
| 563 |
+
label_comp_id;
|
| 564 |
+
}
|
| 565 |
+
|
| 566 |
+
std::vector<bool> nonpoly_mask;
|
| 567 |
+
nonpoly_mask.reserve(nonpoly_asym_ids.size());
|
| 568 |
+
for (int i = 0; i < nonpoly_asym_ids.size(); ++i) {
|
| 569 |
+
absl::string_view nonpoly_asym_id = nonpoly_asym_ids[i];
|
| 570 |
+
absl::string_view nonpoly_auth_seq_id = nonpoly_auth_seq_ids[i];
|
| 571 |
+
absl::string_view nonpoly_ins_code = nonpoly_pdb_ins_codes[i];
|
| 572 |
+
// Remap unknown to unset.
|
| 573 |
+
nonpoly_ins_code = nonpoly_ins_code == "?" ? "." : nonpoly_ins_code;
|
| 574 |
+
absl::string_view nonpoly_mon_id = nonpoly_mon_ids[i];
|
| 575 |
+
|
| 576 |
+
auto it = selected.find(std::make_tuple(
|
| 577 |
+
nonpoly_asym_id, nonpoly_auth_seq_id, nonpoly_ins_code));
|
| 578 |
+
if (it != selected.end()) {
|
| 579 |
+
nonpoly_mask.push_back(it->second == nonpoly_mon_id);
|
| 580 |
+
} else {
|
| 581 |
+
nonpoly_mask.push_back(true); // Missing residues are not heterogeneous.
|
| 582 |
+
}
|
| 583 |
+
}
|
| 584 |
+
|
| 585 |
+
std::vector<bool> branch_mask;
|
| 586 |
+
branch_mask.reserve(branch_asym_ids.size());
|
| 587 |
+
for (int i = 0; i < branch_asym_ids.size(); ++i) {
|
| 588 |
+
absl::string_view branch_asym_id = branch_asym_ids[i];
|
| 589 |
+
absl::string_view branch_auth_seq_id = branch_auth_seq_ids[i];
|
| 590 |
+
|
| 591 |
+
// Insertion codes in _pdbx_branch_scheme are not required and can be
|
| 592 |
+
// missing. Default to unset ('.') in such case.
|
| 593 |
+
absl::string_view branch_ins_code;
|
| 594 |
+
if (i < branch_pdb_ins_codes.size()) {
|
| 595 |
+
branch_ins_code = branch_pdb_ins_codes[i];
|
| 596 |
+
// Remap unknown to unset.
|
| 597 |
+
branch_ins_code = branch_ins_code == "?" ? "." : branch_ins_code;
|
| 598 |
+
} else {
|
| 599 |
+
branch_ins_code = ".";
|
| 600 |
+
}
|
| 601 |
+
|
| 602 |
+
absl::string_view branch_mon_id = branch_mon_ids[i];
|
| 603 |
+
|
| 604 |
+
auto it = selected.find(
|
| 605 |
+
std::make_tuple(branch_asym_id, branch_auth_seq_id, branch_ins_code));
|
| 606 |
+
if (it != selected.end()) {
|
| 607 |
+
branch_mask.push_back(it->second == branch_mon_id);
|
| 608 |
+
} else {
|
| 609 |
+
branch_mask.push_back(true); // Missing residues are not heterogeneous.
|
| 610 |
+
}
|
| 611 |
+
}
|
| 612 |
+
|
| 613 |
+
return std::make_pair(nonpoly_mask, branch_mask);
|
| 614 |
+
}
|
| 615 |
+
|
| 616 |
+
constexpr char kReadMmcifLayout[] = R"(
|
| 617 |
+
Returns the layout of the cif_dict.
|
| 618 |
+
|
| 619 |
+
Args:
|
| 620 |
+
mmcif: mmCIF to calculate the layout for.
|
| 621 |
+
model_id: If non-empty the layout of the given model is returned
|
| 622 |
+
otherwise the layout of all models are returned.
|
| 623 |
+
Raises:
|
| 624 |
+
ValueError: if the mmCIF is malformed or the number of atoms in each
|
| 625 |
+
model are inconsistent.
|
| 626 |
+
)";
|
| 627 |
+
|
| 628 |
+
constexpr char kMmcifFilter[] = R"(
|
| 629 |
+
Returns NumpyArray of selected rows in `_atom_site` and new layout.
|
| 630 |
+
|
| 631 |
+
Args:
|
| 632 |
+
mmcif: mmCIF to filter.
|
| 633 |
+
include_nucleotides: Whether to include polymer entities of type:
|
| 634 |
+
"polypeptide(L)\", "polydeoxyribonucleotide", "polyribonucleotide".
|
| 635 |
+
Otherwise only "polypeptide(L)\". ("polypeptide(D)\" is never included.)
|
| 636 |
+
include_ligands: Whether to include non-polymer entities of type:
|
| 637 |
+
"non-polymer", "branched".
|
| 638 |
+
include_water: Whether to include entities of type water.
|
| 639 |
+
include_other: Whether to include other (non-standard) entity types
|
| 640 |
+
that are not covered by any of the above parameters.
|
| 641 |
+
model_id: If non-empty the model with given name is selected otherwise
|
| 642 |
+
all models are selected.
|
| 643 |
+
|
| 644 |
+
Returns:
|
| 645 |
+
A tuple containing a numpy array with a shape (num_models, num_atoms)
|
| 646 |
+
with the atom_site indices selected and the new layout.
|
| 647 |
+
|
| 648 |
+
Raises:
|
| 649 |
+
ValueError error if mmCIF dict does not have all required fields.
|
| 650 |
+
)";
|
| 651 |
+
|
| 652 |
+
constexpr char kMmcifFixResidues[] = R"(
|
| 653 |
+
Fixes residue columns in-place.
|
| 654 |
+
|
| 655 |
+
Args:
|
| 656 |
+
layout: layout from filter command.
|
| 657 |
+
comp_id: '_atom_site.label_comp_id' of first model.
|
| 658 |
+
group: '_atom_site.group_PDB' of first model.
|
| 659 |
+
atom_id: '_atom_site.label_atom_id' of first model.
|
| 660 |
+
type_symbol: '_atom_site.type_symbol' of first model.
|
| 661 |
+
atom_x: '_atom_site.Cartn_x' of first model.
|
| 662 |
+
atom_y: '_atom_site.Cartn_y' of first model.
|
| 663 |
+
atom_z: '_atom_site.Cartn_z' of first model.
|
| 664 |
+
fix_mse: Whether to convert MSE residues into MET residues.
|
| 665 |
+
fix_arg: Whether to ensure the atoms in ARG are in the correct order.
|
| 666 |
+
fix_unknown_dna: Whether to convert DNA residues from N to DN.
|
| 667 |
+
dna_mask: Which atoms are from DNA chains.
|
| 668 |
+
|
| 669 |
+
Raises:
|
| 670 |
+
ValueError: If shapes are invalid.
|
| 671 |
+
)";
|
| 672 |
+
|
| 673 |
+
constexpr char kSelectedPolymerResidueMask[] = R"(
|
| 674 |
+
Returns a _pdbx_poly_seq_scheme mask for selected hetero residues.
|
| 675 |
+
|
| 676 |
+
Should be called after filtering the layout using mmcif_utils.filter.
|
| 677 |
+
|
| 678 |
+
Args:
|
| 679 |
+
layout: Layout defining the _atom_site residue selection.
|
| 680 |
+
atom_site_label_asym_ids: Internal (label) chain ID, per selected residue.
|
| 681 |
+
atom_site_label_seq_ids: Internal (label) residue ID, per selected residue.
|
| 682 |
+
atom_site_label_comp_ids: Residue name, per selected residue.
|
| 683 |
+
poly_seq_asym_ids: Internal (label) chain ID, per residue.
|
| 684 |
+
poly_seq_seq_ids: Internal (label) residue ID, per residue.
|
| 685 |
+
poly_seq_mon_ids: Residue name, per residue.
|
| 686 |
+
|
| 687 |
+
Returns:
|
| 688 |
+
A mask for the _pdbx_poly_seq_scheme table. If residues are selected
|
| 689 |
+
using this mask, they will have consistent heterogeneous residue
|
| 690 |
+
selection with the _atom_site table.
|
| 691 |
+
)";
|
| 692 |
+
|
| 693 |
+
constexpr char kSelectedLigandResidueMask[] = R"(
|
| 694 |
+
Returns masks for selected ligand hetero residues.
|
| 695 |
+
|
| 696 |
+
Should be called after filtering the layout using mmcif_utils.filter.
|
| 697 |
+
|
| 698 |
+
Args:
|
| 699 |
+
layout: Layout defining the _atom_site residue selection.
|
| 700 |
+
atom_site_label_asym_ids: Internal (label) chain ID, per selected residue.
|
| 701 |
+
atom_site_label_seq_ids: Internal (author) residue ID, per selected residue.
|
| 702 |
+
atom_site_auth_seq_ids: External (author) residue ID, per selected residue.
|
| 703 |
+
atom_site_label_comp_ids: Residue name, per selected residue.
|
| 704 |
+
atom_site_pdbx_pdb_ins_codes: Insertion code, per selected residue.
|
| 705 |
+
nonpoly_asym_ids: Internal (label) chain ID, per residue from
|
| 706 |
+
_pdbx_nonpoly_scheme.
|
| 707 |
+
nonpoly_auth_seq_ids: External (author) residue ID, per residue from
|
| 708 |
+
_pdbx_nonpoly_scheme.
|
| 709 |
+
nonpoly_pdb_ins_codes: Residue name, per residue from
|
| 710 |
+
_pdbx_nonpoly_scheme.
|
| 711 |
+
nonpoly_mon_ids: Insertion code, per residue from _pdbx_nonpoly_scheme.
|
| 712 |
+
branch_asym_ids: Internal (label) chain ID, per residue from
|
| 713 |
+
_pdbx_branch_scheme.
|
| 714 |
+
branch_auth_seq_ids: External (author) residue ID, per residue from
|
| 715 |
+
_pdbx_branch_scheme.
|
| 716 |
+
branch_pdb_ins_codes: Residue name, per residue from _pdbx_branch_scheme.
|
| 717 |
+
branch_mon_ids: Insertion code, per residue from _pdbx_branch_scheme.
|
| 718 |
+
|
| 719 |
+
Returns:
|
| 720 |
+
A tuple with masks for _pdbx_nonpoly_scheme and _pdbx_branch_scheme. If
|
| 721 |
+
residues are selected using these masks, they will have consistent
|
| 722 |
+
heterogeneous residue selection with the _atom_site table.
|
| 723 |
+
)";
|
| 724 |
+
|
| 725 |
+
} // namespace
|
| 726 |
+
|
| 727 |
+
void RegisterModuleMmcifUtils(pybind11::module m) {
|
| 728 |
+
m.def("read_layout", ReadMmcifLayout,
|
| 729 |
+
py::arg("mmcif"), //
|
| 730 |
+
py::arg("model_id") = "", //
|
| 731 |
+
py::doc(kReadMmcifLayout + 1) //
|
| 732 |
+
);
|
| 733 |
+
|
| 734 |
+
m.def("filter", MmcifFilter, //
|
| 735 |
+
py::arg("mmcif"), //
|
| 736 |
+
py::arg("include_nucleotides"), //
|
| 737 |
+
py::arg("include_ligands") = false, //
|
| 738 |
+
py::arg("include_water") = false, //
|
| 739 |
+
py::arg("include_other") = false, //
|
| 740 |
+
py::arg("model_id") = "", //
|
| 741 |
+
py::doc(kMmcifFilter + 1) //
|
| 742 |
+
);
|
| 743 |
+
|
| 744 |
+
m.def("fix_residues", MmcifFixResidues,
|
| 745 |
+
py::arg("layout"), //
|
| 746 |
+
py::arg("comp_id"), //
|
| 747 |
+
py::arg("atom_id"), //
|
| 748 |
+
py::arg("atom_x"), //
|
| 749 |
+
py::arg("atom_y"), //
|
| 750 |
+
py::arg("atom_z"), //
|
| 751 |
+
py::arg("fix_arg") = false, //
|
| 752 |
+
py::doc(kMmcifFixResidues + 1) //
|
| 753 |
+
);
|
| 754 |
+
|
| 755 |
+
m.def("selected_polymer_residue_mask", SelectedPolymerResidueMask,
|
| 756 |
+
py::arg("layout"), //
|
| 757 |
+
py::arg("atom_site_label_asym_ids"), //
|
| 758 |
+
py::arg("atom_site_label_seq_ids"), //
|
| 759 |
+
py::arg("atom_site_label_comp_ids"), //
|
| 760 |
+
py::arg("poly_seq_asym_ids"), //
|
| 761 |
+
py::arg("poly_seq_seq_ids"), //
|
| 762 |
+
py::arg("poly_seq_mon_ids"), //
|
| 763 |
+
py::call_guard<py::gil_scoped_release>(), //
|
| 764 |
+
py::doc(kSelectedPolymerResidueMask + 1) //
|
| 765 |
+
);
|
| 766 |
+
|
| 767 |
+
m.def("selected_ligand_residue_mask", SelectedLigandResidueMask,
|
| 768 |
+
py::arg("layout"), //
|
| 769 |
+
py::arg("atom_site_label_asym_ids"), //
|
| 770 |
+
py::arg("atom_site_label_seq_ids"), //
|
| 771 |
+
py::arg("atom_site_auth_seq_ids"), //
|
| 772 |
+
py::arg("atom_site_label_comp_ids"), //
|
| 773 |
+
py::arg("atom_site_pdbx_pdb_ins_codes"), //
|
| 774 |
+
py::arg("nonpoly_asym_ids"), //
|
| 775 |
+
py::arg("nonpoly_auth_seq_ids"), //
|
| 776 |
+
py::arg("nonpoly_pdb_ins_codes"), //
|
| 777 |
+
py::arg("nonpoly_mon_ids"), //
|
| 778 |
+
py::arg("branch_asym_ids"), //
|
| 779 |
+
py::arg("branch_auth_seq_ids"), //
|
| 780 |
+
py::arg("branch_pdb_ins_codes"), //
|
| 781 |
+
py::arg("branch_mon_ids"), //
|
| 782 |
+
py::call_guard<py::gil_scoped_release>(), //
|
| 783 |
+
py::doc(kSelectedLigandResidueMask + 1) //
|
| 784 |
+
);
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
} // namespace alphafold3
|
flax_model/alphafold3/structure/cpp/mmcif_utils_pybind.h
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_UTILS_PYBIND_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_UTILS_PYBIND_H_
|
| 15 |
+
|
| 16 |
+
#include "pybind11/pybind11.h"
|
| 17 |
+
|
| 18 |
+
namespace alphafold3 {
|
| 19 |
+
|
| 20 |
+
void RegisterModuleMmcifUtils(pybind11::module m);
|
| 21 |
+
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_MMCIF_UTILS_PYBIND_H_
|
flax_model/alphafold3/structure/cpp/string_array.pyi
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
from collections.abc import Sequence
|
| 4 |
+
from typing import Any, overload
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def format_float_array(
|
| 10 |
+
values: Sequence[float], num_decimal_places: int
|
| 11 |
+
) -> list[str]: ...
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def isin(
|
| 15 |
+
array: np.ndarray[object],
|
| 16 |
+
test_elements: set[str | bytes],
|
| 17 |
+
*,
|
| 18 |
+
invert: bool = ...,
|
| 19 |
+
) -> np.ndarray[bool]: ...
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@overload
|
| 23 |
+
def remap(
|
| 24 |
+
array: np.ndarray[object],
|
| 25 |
+
mapping: dict[str, str],
|
| 26 |
+
default_value: str,
|
| 27 |
+
inplace: bool = ...,
|
| 28 |
+
) -> np.ndarray[object]: ...
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@overload
|
| 32 |
+
def remap(
|
| 33 |
+
array: np.ndarray[object],
|
| 34 |
+
mapping: dict[str, str],
|
| 35 |
+
inplace: bool = ...,
|
| 36 |
+
) -> np.ndarray[object]: ...
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def remap_multiple(
|
| 40 |
+
arrays: Sequence[np.ndarray[object]],
|
| 41 |
+
mapping: dict[tuple[Any], int],
|
| 42 |
+
) -> np.ndarray[int]: ...
|
flax_model/alphafold3/structure/cpp/string_array_pybind.cc
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
//
|
| 3 |
+
// AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
// this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
//
|
| 6 |
+
// To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
// out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
// if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
// https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
#include <Python.h>
|
| 12 |
+
|
| 13 |
+
#include <algorithm>
|
| 14 |
+
#include <cstddef>
|
| 15 |
+
#include <cstdint>
|
| 16 |
+
#include <cstring>
|
| 17 |
+
#include <iterator>
|
| 18 |
+
#include <limits>
|
| 19 |
+
#include <string>
|
| 20 |
+
#include <vector>
|
| 21 |
+
|
| 22 |
+
#include "numpy/arrayobject.h"
|
| 23 |
+
#include "numpy/ndarrayobject.h"
|
| 24 |
+
#include "numpy/ndarraytypes.h"
|
| 25 |
+
#include "numpy/npy_common.h"
|
| 26 |
+
#include "absl/algorithm/container.h"
|
| 27 |
+
#include "absl/container/flat_hash_set.h"
|
| 28 |
+
#include "absl/strings/str_format.h"
|
| 29 |
+
#include "absl/strings/string_view.h"
|
| 30 |
+
#include "absl/types/span.h"
|
| 31 |
+
#include "pybind11/cast.h"
|
| 32 |
+
#include "pybind11/numpy.h"
|
| 33 |
+
#include "pybind11/pybind11.h"
|
| 34 |
+
#include "pybind11/pytypes.h"
|
| 35 |
+
#include "pybind11_abseil/absl_casters.h"
|
| 36 |
+
|
| 37 |
+
namespace {
|
| 38 |
+
|
| 39 |
+
namespace py = pybind11;
|
| 40 |
+
|
| 41 |
+
PyObject* RemapNumpyArrayObjects(PyObject* array, PyObject* mapping,
|
| 42 |
+
bool inplace, PyObject* default_value) {
|
| 43 |
+
import_array();
|
| 44 |
+
if (!PyArray_Check(array)) {
|
| 45 |
+
PyErr_SetString(PyExc_TypeError, "'array' must be a np.ndarray.");
|
| 46 |
+
return nullptr;
|
| 47 |
+
}
|
| 48 |
+
if (!PyDict_Check(mapping)) {
|
| 49 |
+
PyErr_SetString(PyExc_TypeError, "'mapping' must be a Python dict.");
|
| 50 |
+
return nullptr;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
PyArrayObject* array_obj = reinterpret_cast<PyArrayObject*>(array);
|
| 54 |
+
if (PyArray_TYPE(array_obj) != NPY_OBJECT) {
|
| 55 |
+
PyErr_SetString(PyExc_TypeError, "`array` must be an array of objects.");
|
| 56 |
+
return nullptr;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
if (inplace) {
|
| 60 |
+
// We are returning original array so we need to increase the ref count.
|
| 61 |
+
Py_INCREF(array);
|
| 62 |
+
} else {
|
| 63 |
+
// We are returning a fresh copy.
|
| 64 |
+
array = PyArray_NewCopy(array_obj, NPY_CORDER);
|
| 65 |
+
if (array == nullptr) {
|
| 66 |
+
PyErr_SetString(PyExc_MemoryError, "Out of memory!");
|
| 67 |
+
return nullptr;
|
| 68 |
+
}
|
| 69 |
+
array_obj = reinterpret_cast<PyArrayObject*>(array);
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
if (PyArray_SIZE(array_obj) == 0) {
|
| 73 |
+
return array;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
if (default_value == nullptr && PyDict_Size(mapping) == 0) {
|
| 77 |
+
return array;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
NpyIter* iter = NpyIter_New(
|
| 81 |
+
array_obj, NPY_ITER_READWRITE | NPY_ITER_EXTERNAL_LOOP | NPY_ITER_REFS_OK,
|
| 82 |
+
NPY_KEEPORDER, NPY_NO_CASTING, nullptr);
|
| 83 |
+
if (iter == nullptr) {
|
| 84 |
+
PyErr_SetString(PyExc_MemoryError, "Out of memory!");
|
| 85 |
+
Py_XDECREF(array);
|
| 86 |
+
return nullptr;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
NpyIter_IterNextFunc* iter_next = NpyIter_GetIterNext(iter, nullptr);
|
| 90 |
+
if (iter_next == nullptr) {
|
| 91 |
+
NpyIter_Deallocate(iter);
|
| 92 |
+
Py_XDECREF(array);
|
| 93 |
+
PyErr_SetString(PyExc_MemoryError, "Out of memory!");
|
| 94 |
+
return nullptr;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
// Iterating arrays taken from:
|
| 98 |
+
// https://numpy.org/doc/stable/reference/c-api/iterator.html
|
| 99 |
+
char** data_pointer = NpyIter_GetDataPtrArray(iter);
|
| 100 |
+
npy_intp* stride_pointer = NpyIter_GetInnerStrideArray(iter);
|
| 101 |
+
npy_intp* inner_size_pointer = NpyIter_GetInnerLoopSizePtr(iter);
|
| 102 |
+
do {
|
| 103 |
+
char* data = *data_pointer;
|
| 104 |
+
npy_intp stride = *stride_pointer;
|
| 105 |
+
npy_intp count = *inner_size_pointer;
|
| 106 |
+
for (size_t i = 0; i < count; ++i) {
|
| 107 |
+
PyObject* entry;
|
| 108 |
+
std::memcpy(&entry, data, sizeof(PyObject*));
|
| 109 |
+
PyObject* result = PyDict_GetItem(mapping, entry);
|
| 110 |
+
if (result != nullptr) {
|
| 111 |
+
// Replace entry.
|
| 112 |
+
Py_INCREF(result);
|
| 113 |
+
Py_XDECREF(entry);
|
| 114 |
+
std::memcpy(data, &result, sizeof(PyObject*));
|
| 115 |
+
} else if (default_value != nullptr) {
|
| 116 |
+
// Replace entry with a default value.
|
| 117 |
+
Py_INCREF(default_value);
|
| 118 |
+
Py_XDECREF(entry);
|
| 119 |
+
std::memcpy(data, &default_value, sizeof(PyObject*));
|
| 120 |
+
}
|
| 121 |
+
data += stride;
|
| 122 |
+
}
|
| 123 |
+
} while (iter_next(iter));
|
| 124 |
+
|
| 125 |
+
NpyIter_Deallocate(iter);
|
| 126 |
+
return array;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
// Convert 1D Numpy float array to a list of strings where each string has fixed
|
| 130 |
+
// number of decimal points. This is faster than Python list comprehension.
|
| 131 |
+
std::vector<std::string> FormatFloatArray(absl::Span<const float> values,
|
| 132 |
+
int num_decimal_places) {
|
| 133 |
+
std::vector<std::string> output;
|
| 134 |
+
output.reserve(values.size());
|
| 135 |
+
|
| 136 |
+
absl::c_transform(values, std::back_inserter(output),
|
| 137 |
+
[num_decimal_places](float value) {
|
| 138 |
+
return absl::StrFormat("%.*f", num_decimal_places, value);
|
| 139 |
+
});
|
| 140 |
+
return output;
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
py::array_t<bool> IsIn(
|
| 144 |
+
const py::array_t<PyObject*, py::array::c_style>& array,
|
| 145 |
+
const absl::flat_hash_set<absl::string_view>& test_elements, bool invert) {
|
| 146 |
+
const size_t num_elements = array.size();
|
| 147 |
+
py::array_t<bool> output(num_elements);
|
| 148 |
+
std::fill(output.mutable_data(), output.mutable_data() + output.size(),
|
| 149 |
+
invert);
|
| 150 |
+
|
| 151 |
+
// Shortcut: The output will be trivially always false if test_elements empty.
|
| 152 |
+
if (test_elements.empty()) {
|
| 153 |
+
return output;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
for (size_t i = 0; i < num_elements; ++i) {
|
| 157 |
+
// Compare the string values instead of comparing just object pointers.
|
| 158 |
+
py::handle handle = array.data()[i];
|
| 159 |
+
if (!PyUnicode_Check(handle.ptr()) && !PyBytes_Check(handle.ptr())) {
|
| 160 |
+
continue;
|
| 161 |
+
}
|
| 162 |
+
if (test_elements.contains(py::cast<absl::string_view>(handle))) {
|
| 163 |
+
output.mutable_data()[i] = !invert;
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
if (array.ndim() > 1) {
|
| 167 |
+
auto shape =
|
| 168 |
+
std::vector<ptrdiff_t>(array.shape(), array.shape() + array.ndim());
|
| 169 |
+
return output.reshape(shape);
|
| 170 |
+
}
|
| 171 |
+
return output;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
py::array RemapMultipleArrays(
|
| 175 |
+
const std::vector<py::array_t<PyObject*, py::array::c_style>>& arrays,
|
| 176 |
+
const py::dict& mapping) {
|
| 177 |
+
size_t array_size = arrays[0].size();
|
| 178 |
+
for (const auto& array : arrays) {
|
| 179 |
+
if (array.size() != array_size) {
|
| 180 |
+
throw py::value_error("All arrays must have the same length.");
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
// Create a result buffer.
|
| 185 |
+
auto result = py::array_t<int64_t>(array_size);
|
| 186 |
+
absl::Span<int64_t> result_buffer(result.mutable_data(), array_size);
|
| 187 |
+
PyObject* entry = PyTuple_New(arrays.size());
|
| 188 |
+
if (entry == nullptr) {
|
| 189 |
+
throw py::error_already_set();
|
| 190 |
+
}
|
| 191 |
+
std::vector<absl::Span<PyObject* const>> array_spans;
|
| 192 |
+
array_spans.reserve(arrays.size());
|
| 193 |
+
for (const auto& array : arrays) {
|
| 194 |
+
array_spans.emplace_back(array.data(), array.size());
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
// Iterate over arrays and look up elements in the `py_dict`.
|
| 198 |
+
bool fail = false;
|
| 199 |
+
for (size_t i = 0; i < array_size; ++i) {
|
| 200 |
+
for (size_t j = 0; j < array_spans.size(); ++j) {
|
| 201 |
+
PyTuple_SET_ITEM(entry, j, array_spans[j][i]);
|
| 202 |
+
}
|
| 203 |
+
PyObject* result = PyDict_GetItem(mapping.ptr(), entry);
|
| 204 |
+
if (result != nullptr) {
|
| 205 |
+
int64_t result_value = PyLong_AsLongLong(result);
|
| 206 |
+
if (result_value == -1 && PyErr_Occurred()) {
|
| 207 |
+
fail = true;
|
| 208 |
+
break;
|
| 209 |
+
}
|
| 210 |
+
if (result_value > std::numeric_limits<int64_t>::max() ||
|
| 211 |
+
result_value < std::numeric_limits<int64_t>::lowest()) {
|
| 212 |
+
PyErr_SetString(PyExc_OverflowError, "Result value too large.");
|
| 213 |
+
fail = true;
|
| 214 |
+
break;
|
| 215 |
+
}
|
| 216 |
+
result_buffer[i] = result_value;
|
| 217 |
+
} else {
|
| 218 |
+
PyErr_Format(PyExc_KeyError, "%R", entry);
|
| 219 |
+
fail = true;
|
| 220 |
+
break;
|
| 221 |
+
}
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
for (size_t j = 0; j < array_spans.size(); ++j) {
|
| 225 |
+
PyTuple_SET_ITEM(entry, j, nullptr);
|
| 226 |
+
}
|
| 227 |
+
Py_XDECREF(entry);
|
| 228 |
+
if (fail) {
|
| 229 |
+
throw py::error_already_set();
|
| 230 |
+
}
|
| 231 |
+
return result;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
constexpr char kRemapNumpyArrayObjects[] = R"(
|
| 235 |
+
Replace objects in NumPy array of objects using mapping.
|
| 236 |
+
|
| 237 |
+
Args:
|
| 238 |
+
array: NumPy array with dtype=object.
|
| 239 |
+
mapping: Dict mapping old values to new values.
|
| 240 |
+
inplace: Bool (default False) whether to replace values inplace or to
|
| 241 |
+
create a new array.
|
| 242 |
+
default_value: If given, what value to map to if the mapping is missing
|
| 243 |
+
for that particular item. If not given, such items are left unchanged.
|
| 244 |
+
|
| 245 |
+
Returns
|
| 246 |
+
NumPy array of dtype object with values replaced according to mapping.
|
| 247 |
+
If inplace is True the original array is modified inplace otherwise a
|
| 248 |
+
new array is returned.
|
| 249 |
+
)";
|
| 250 |
+
|
| 251 |
+
constexpr char kFormatFloatArrayDoc[] = R"(
|
| 252 |
+
Converts float -> string array with given number of decimal places.
|
| 253 |
+
)";
|
| 254 |
+
|
| 255 |
+
constexpr char kIsInDoc[] = R"(
|
| 256 |
+
Computes whether each element is in test_elements.
|
| 257 |
+
|
| 258 |
+
Same use as np.isin, but much faster. If len(array) = n, len(test_elements) = m:
|
| 259 |
+
* This function has complexity O(n).
|
| 260 |
+
* np.isin with arrays of objects has complexity O(m*log(m) + n * log(m)).
|
| 261 |
+
|
| 262 |
+
Args:
|
| 263 |
+
array: Input NumPy array with dtype=object.
|
| 264 |
+
test_elements: The values against which to test each value of array.
|
| 265 |
+
invert: If True, the values in the returned array are inverted, as if
|
| 266 |
+
calculating `element not in test_elements`. Default is False.
|
| 267 |
+
`isin(a, b, invert=True)` is equivalent to but faster than `~isin(a, b)`.
|
| 268 |
+
|
| 269 |
+
Returns
|
| 270 |
+
A boolean array of the same shape as the input array. Each value `val` is:
|
| 271 |
+
* `val in test_elements` if `invert=False`,
|
| 272 |
+
* `val not in test_elements` if `invert=True`.
|
| 273 |
+
)";
|
| 274 |
+
|
| 275 |
+
constexpr char kRemapMultipleDoc[] = R"(
|
| 276 |
+
Maps keys from multiple aligned arrays to a single array.
|
| 277 |
+
|
| 278 |
+
Args:
|
| 279 |
+
arrays: Numpy arrays of the same length. The tuple of aligned entries is used
|
| 280 |
+
as key for the mapping.
|
| 281 |
+
mapping: Dict mapping from tuples to integer values.
|
| 282 |
+
|
| 283 |
+
Returns
|
| 284 |
+
NumPy array of dtype `int` with values looked up in mapping according to the
|
| 285 |
+
tuple of aligned array entries as keys.
|
| 286 |
+
)";
|
| 287 |
+
|
| 288 |
+
} // namespace
|
| 289 |
+
|
| 290 |
+
namespace alphafold3 {
|
| 291 |
+
|
| 292 |
+
void RegisterModuleStringArray(pybind11::module m) {
|
| 293 |
+
m.def(
|
| 294 |
+
"remap",
|
| 295 |
+
[](py::object array, py::object mapping, bool inplace,
|
| 296 |
+
py::object default_value) -> py::object {
|
| 297 |
+
PyObject* result = RemapNumpyArrayObjects(array.ptr(), mapping.ptr(),
|
| 298 |
+
inplace, default_value.ptr());
|
| 299 |
+
if (result == nullptr) {
|
| 300 |
+
throw py::error_already_set();
|
| 301 |
+
}
|
| 302 |
+
return py::reinterpret_steal<py::object>(result);
|
| 303 |
+
},
|
| 304 |
+
py::return_value_policy::take_ownership, py::arg("array"),
|
| 305 |
+
py::arg("mapping"), py::arg("inplace") = false, py::arg("default_value"),
|
| 306 |
+
py::doc(kRemapNumpyArrayObjects + 1));
|
| 307 |
+
m.def(
|
| 308 |
+
"remap",
|
| 309 |
+
[](py::object array, py::object mapping, bool inplace) -> py::object {
|
| 310 |
+
PyObject* result = RemapNumpyArrayObjects(array.ptr(), mapping.ptr(),
|
| 311 |
+
inplace, nullptr);
|
| 312 |
+
if (result == nullptr) {
|
| 313 |
+
throw py::error_already_set();
|
| 314 |
+
}
|
| 315 |
+
return py::reinterpret_steal<py::object>(result);
|
| 316 |
+
},
|
| 317 |
+
py::return_value_policy::take_ownership, py::arg("array"),
|
| 318 |
+
py::arg("mapping"), py::arg("inplace") = false,
|
| 319 |
+
py::doc(kRemapNumpyArrayObjects + 1));
|
| 320 |
+
m.def("format_float_array", &FormatFloatArray, py::arg("values"),
|
| 321 |
+
py::arg("num_decimal_places"), py::doc(kFormatFloatArrayDoc + 1),
|
| 322 |
+
py::call_guard<py::gil_scoped_release>());
|
| 323 |
+
m.def("isin", &IsIn, py::arg("array"), py::arg("test_elements"),
|
| 324 |
+
py::kw_only(), py::arg("invert") = false, py::doc(kIsInDoc + 1));
|
| 325 |
+
m.def("remap_multiple", &RemapMultipleArrays, py::arg("arrays"),
|
| 326 |
+
py::arg("mapping"), py::doc(kRemapMultipleDoc + 1));
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
} // namespace alphafold3
|
flax_model/alphafold3/structure/cpp/string_array_pybind.h
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 2024 DeepMind Technologies Limited
|
| 3 |
+
*
|
| 4 |
+
* AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 5 |
+
* this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 6 |
+
*
|
| 7 |
+
* To request access to the AlphaFold 3 model parameters, follow the process set
|
| 8 |
+
* out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 9 |
+
* if received directly from Google. Use is subject to terms of use available at
|
| 10 |
+
* https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 11 |
+
*/
|
| 12 |
+
|
| 13 |
+
#ifndef ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_STRING_ARRAY_PYBIND_H_
|
| 14 |
+
#define ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_STRING_ARRAY_PYBIND_H_
|
| 15 |
+
|
| 16 |
+
#include "pybind11/pybind11.h"
|
| 17 |
+
|
| 18 |
+
namespace alphafold3 {
|
| 19 |
+
|
| 20 |
+
void RegisterModuleStringArray(pybind11::module m);
|
| 21 |
+
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
#endif // ALPHAFOLD3_SRC_ALPHAFOLD3_STRUCTURE_PYTHON_STRING_ARRAY_PYBIND_H_
|
flax_model/alphafold3/structure/mmcif.py
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
"""Low level mmCIF parsing operations and wrappers for nicer C++/Py errors.
|
| 4 |
+
|
| 5 |
+
Note that the cif_dict.CifDict class has many useful methods to help with data
|
| 6 |
+
extraction which are not shown in this file. You can find them in cif_dict.clif
|
| 7 |
+
together with docstrings. The cif_dict.CifDict class behaves like an immutable
|
| 8 |
+
Python dictionary (some methods are not implemented though).
|
| 9 |
+
"""
|
| 10 |
+
from collections.abc import Callable, Mapping, Sequence
|
| 11 |
+
import functools
|
| 12 |
+
import itertools
|
| 13 |
+
import re
|
| 14 |
+
from typing import ParamSpec, TypeAlias, TypeVar
|
| 15 |
+
|
| 16 |
+
from flax_model.alphafold3.constants import chemical_components
|
| 17 |
+
from flax_model.alphafold3.cpp import cif_dict
|
| 18 |
+
from flax_model.alphafold3.cpp import mmcif_atom_site
|
| 19 |
+
from flax_model.alphafold3.cpp import mmcif_struct_conn
|
| 20 |
+
from flax_model.alphafold3.cpp import string_array
|
| 21 |
+
import numpy as np
|
| 22 |
+
|
| 23 |
+
Mmcif = cif_dict.CifDict
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
_P = ParamSpec('_P')
|
| 27 |
+
_T = TypeVar('_T')
|
| 28 |
+
_WappedFn: TypeAlias = Callable[_P, _T]
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
@functools.lru_cache(maxsize=256)
|
| 32 |
+
def int_id_to_str_id(num: int) -> str:
|
| 33 |
+
"""Encodes a number as a string, using reverse spreadsheet style naming.
|
| 34 |
+
|
| 35 |
+
Args:
|
| 36 |
+
num: A positive integer.
|
| 37 |
+
|
| 38 |
+
Returns:
|
| 39 |
+
A string that encodes the positive integer using reverse spreadsheet style,
|
| 40 |
+
naming e.g. 1 = A, 2 = B, ..., 27 = AA, 28 = BA, 29 = CA, ... This is the
|
| 41 |
+
usual way to encode chain IDs in mmCIF files.
|
| 42 |
+
"""
|
| 43 |
+
if num <= 0:
|
| 44 |
+
raise ValueError(f'Only positive integers allowed, got {num}.')
|
| 45 |
+
|
| 46 |
+
num = num - 1 # 1-based indexing.
|
| 47 |
+
output = []
|
| 48 |
+
while num >= 0:
|
| 49 |
+
output.append(chr(num % 26 + ord('A')))
|
| 50 |
+
num = num // 26 - 1
|
| 51 |
+
return ''.join(output)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
@functools.lru_cache(maxsize=256)
|
| 55 |
+
def str_id_to_int_id(str_id: str) -> int:
|
| 56 |
+
"""Encodes an mmCIF-style string chain ID as an integer.
|
| 57 |
+
|
| 58 |
+
The integer IDs are one based so this function is the inverse of
|
| 59 |
+
int_id_to_str_id.
|
| 60 |
+
|
| 61 |
+
Args:
|
| 62 |
+
str_id: A string chain ID consisting only of upper case letters A-Z.
|
| 63 |
+
|
| 64 |
+
Returns:
|
| 65 |
+
An integer that can be used to order mmCIF chain IDs in the standard
|
| 66 |
+
(reverse spreadsheet style) ordering.
|
| 67 |
+
"""
|
| 68 |
+
if not re.match('^[A-Z]+$', str_id):
|
| 69 |
+
raise ValueError(f'String ID must be upper case letters, got {str_id}.')
|
| 70 |
+
|
| 71 |
+
offset = ord('A') - 1
|
| 72 |
+
output = 0
|
| 73 |
+
for i, c in enumerate(str_id):
|
| 74 |
+
output += (ord(c) - offset) * int(26**i)
|
| 75 |
+
return output
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def from_string(mmcif_string: str | bytes) -> Mmcif:
|
| 79 |
+
return cif_dict.from_string(mmcif_string)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def parse_multi_data_cif(cif_string: str) -> dict[str, Mmcif]:
|
| 83 |
+
"""Parses a CIF string with multiple data records.
|
| 84 |
+
|
| 85 |
+
For instance, the CIF string:
|
| 86 |
+
|
| 87 |
+
```
|
| 88 |
+
data_001
|
| 89 |
+
_foo bar
|
| 90 |
+
#
|
| 91 |
+
data_002
|
| 92 |
+
_foo baz
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
is parsed as:
|
| 96 |
+
|
| 97 |
+
```
|
| 98 |
+
{'001': Mmcif({'_foo': ['bar']}), '002': Mmcif({'_foo': ['baz']})}
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
Args:
|
| 102 |
+
cif_string: The multi-data CIF string to be parsed.
|
| 103 |
+
|
| 104 |
+
Returns:
|
| 105 |
+
A dictionary mapping record names to Mmcif objects with data.
|
| 106 |
+
"""
|
| 107 |
+
return cif_dict.parse_multi_data_cif(cif_string)
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
# def tokenize(mmcif_string: str) -> list[str]:
|
| 111 |
+
# return cif_dict.tokenize(mmcif_string)
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
# def split_line(line: str) -> list[str]:
|
| 115 |
+
# return cif_dict.split_line(line)
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class BondParsingError(Exception):
|
| 119 |
+
"""Exception raised by errors when getting bond atom indices."""
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def get_bond_atom_indices(
|
| 123 |
+
mmcif: Mmcif,
|
| 124 |
+
model_id: str = '1',
|
| 125 |
+
) -> tuple[Sequence[int], Sequence[int]]:
|
| 126 |
+
"""Extracts the indices of the atoms that participate in bonds.
|
| 127 |
+
|
| 128 |
+
Args:
|
| 129 |
+
mmcif: The mmCIF object to process.
|
| 130 |
+
model_id: The ID of the model that the returned atoms will belong to. This
|
| 131 |
+
should be a value in the mmCIF's _atom_site.pdbx_PDB_model_num column.
|
| 132 |
+
|
| 133 |
+
Returns:
|
| 134 |
+
Two lists of atom indices, `from_atoms` and `to_atoms`, each one having
|
| 135 |
+
length num_bonds (as defined by _struct_conn, the bonds table). The bond
|
| 136 |
+
i, defined by the i'th row in _struct_conn, is a bond from atom at index
|
| 137 |
+
from_atoms[i], to the atom at index to_atoms[i]. The indices are simple
|
| 138 |
+
0-based indexes into the columns of the _atom_site table in the input
|
| 139 |
+
mmCIF, and do not necessarily correspond to the values in _atom_site.id,
|
| 140 |
+
or any other column.
|
| 141 |
+
|
| 142 |
+
Raises:
|
| 143 |
+
BondParsingError: If any of the required tables or columns are not present
|
| 144 |
+
in
|
| 145 |
+
the mmCIF, or if the _struct_conn table refers to atoms that cannot
|
| 146 |
+
be found in the _atom_site table.
|
| 147 |
+
"""
|
| 148 |
+
try:
|
| 149 |
+
return mmcif_struct_conn.get_bond_atom_indices(mmcif, model_id)
|
| 150 |
+
except ValueError as e:
|
| 151 |
+
raise BondParsingError(str(e)) from e
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def get_or_infer_type_symbol(
|
| 155 |
+
mmcif: Mmcif, ccd: chemical_components.Ccd | None = None
|
| 156 |
+
) -> Sequence[str]:
|
| 157 |
+
"""Returns the type symbol (element) for all of the atoms.
|
| 158 |
+
|
| 159 |
+
Args:
|
| 160 |
+
mmcif: A parsed mmCIF file in the Mmcif format.
|
| 161 |
+
ccd: The chemical component dictionary. If not provided, defaults to the
|
| 162 |
+
cached CCD.
|
| 163 |
+
|
| 164 |
+
If present, returns the _atom_site.type_symbol. If not, infers it using
|
| 165 |
+
_atom_site.label_comp_id (residue name), _atom_site.label_atom_id (atom name)
|
| 166 |
+
and the CCD.
|
| 167 |
+
"""
|
| 168 |
+
ccd = ccd or chemical_components.Ccd()
|
| 169 |
+
type_symbol_fn = lambda res_name, atom_name: chemical_components.type_symbol(
|
| 170 |
+
ccd, res_name, atom_name
|
| 171 |
+
)
|
| 172 |
+
return mmcif_atom_site.get_or_infer_type_symbol(mmcif, type_symbol_fn)
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def get_chain_type_by_entity_id(mmcif: Mmcif) -> Mapping[str, str]:
|
| 176 |
+
"""Returns mapping from entity ID to its type or polymer type if available.
|
| 177 |
+
|
| 178 |
+
If the entity is in the _entity_poly table, returns its polymer chain type.
|
| 179 |
+
If not, returns the type as specified in the _entity table.
|
| 180 |
+
|
| 181 |
+
Args:
|
| 182 |
+
mmcif: CifDict holding the mmCIF.
|
| 183 |
+
"""
|
| 184 |
+
poly_entity_id = mmcif.get('_entity_poly.entity_id', [])
|
| 185 |
+
poly_type = mmcif.get('_entity_poly.type', [])
|
| 186 |
+
poly_type_by_entity_id = dict(zip(poly_entity_id, poly_type, strict=True))
|
| 187 |
+
|
| 188 |
+
chain_type_by_entity_id = {}
|
| 189 |
+
for entity_id, entity_type in zip(
|
| 190 |
+
mmcif.get('_entity.id', []), mmcif.get('_entity.type', []), strict=True
|
| 191 |
+
):
|
| 192 |
+
chain_type = poly_type_by_entity_id.get(entity_id) or entity_type
|
| 193 |
+
chain_type_by_entity_id[entity_id] = chain_type
|
| 194 |
+
|
| 195 |
+
return chain_type_by_entity_id
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def get_internal_to_author_chain_id_map(mmcif: Mmcif) -> Mapping[str, str]:
|
| 199 |
+
"""Returns a mapping from internal chain ID to the author chain ID.
|
| 200 |
+
|
| 201 |
+
Note that this is not a bijection. One author chain ID can map to multiple
|
| 202 |
+
internal chain IDs. For example, a protein chain and a ligand bound to it will
|
| 203 |
+
share the same author chain ID, but they will each have a unique internal
|
| 204 |
+
chain ID).
|
| 205 |
+
|
| 206 |
+
Args:
|
| 207 |
+
mmcif: CifDict holding the mmCIF.
|
| 208 |
+
"""
|
| 209 |
+
return mmcif_atom_site.get_internal_to_author_chain_id_map(mmcif)
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
def get_experimental_method(mmcif: Mmcif) -> str | None:
|
| 213 |
+
field = '_exptl.method'
|
| 214 |
+
return ','.join(mmcif[field]).lower() if field in mmcif else None
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
def get_release_date(mmcif: Mmcif) -> str | None:
|
| 218 |
+
"""Returns the oldest revision date."""
|
| 219 |
+
if '_pdbx_audit_revision_history.revision_date' not in mmcif:
|
| 220 |
+
return None
|
| 221 |
+
|
| 222 |
+
# Release dates are ISO-8601, hence sort well.
|
| 223 |
+
return min(mmcif['_pdbx_audit_revision_history.revision_date'])
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def get_resolution(mmcif: Mmcif) -> float | None:
|
| 227 |
+
"""Returns the resolution of the structure.
|
| 228 |
+
|
| 229 |
+
More than one resolution can be reported in an mmCIF. This function returns
|
| 230 |
+
the first one (in the order _refine.ls_d_res_high,
|
| 231 |
+
_em_3d_reconstruction.resolution, _reflns.d_resolution_high) that appears
|
| 232 |
+
in the mmCIF as is parseable as a float.
|
| 233 |
+
|
| 234 |
+
Args:
|
| 235 |
+
mmcif: An `Mmcif` object.
|
| 236 |
+
|
| 237 |
+
Returns:
|
| 238 |
+
The resolution as reported in the mmCIF.
|
| 239 |
+
"""
|
| 240 |
+
for res_key in ('_refine.ls_d_res_high',
|
| 241 |
+
'_em_3d_reconstruction.resolution',
|
| 242 |
+
'_reflns.d_resolution_high'):
|
| 243 |
+
if res_key in mmcif:
|
| 244 |
+
try:
|
| 245 |
+
raw_resolution = mmcif[res_key][0]
|
| 246 |
+
return float(raw_resolution)
|
| 247 |
+
except ValueError:
|
| 248 |
+
continue
|
| 249 |
+
return None
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def parse_oper_expr(oper_expression: str) -> list[tuple[str, ...]]:
|
| 253 |
+
"""Determines which transforms to apply based on an MMCIF oper_expression str.
|
| 254 |
+
|
| 255 |
+
Args:
|
| 256 |
+
oper_expression: the field oper_expression from MMCIF format data.
|
| 257 |
+
Transform ids may be either numbers or single letters. Hyphens are used to
|
| 258 |
+
denote a numeric range of transforms to apply, and commas are used to
|
| 259 |
+
delimit a sequence of transforms. Where two sets of parentheses are
|
| 260 |
+
adjacent without a comma, the two sets of transforms should be combined as
|
| 261 |
+
a cartesian product, i.e. all possible pairs.
|
| 262 |
+
example 1,2,3 -> generate 3 copies of each chain by applying 1, 2 or 3.
|
| 263 |
+
example (1-3) -> generate 3 copies of each chain by applying 1, 2 or 3.
|
| 264 |
+
example (1-3)(4-6) -> generate 9 copies of each chain by applying one of
|
| 265 |
+
[(1,4), (1,5), (1,6),
|
| 266 |
+
(2,4), (2,5), (2,6),
|
| 267 |
+
(3,4), (3,5), (3,6)]
|
| 268 |
+
example (P) -> apply transform with id P.
|
| 269 |
+
|
| 270 |
+
Raises:
|
| 271 |
+
ValueError: Failure to parse oper_expression.
|
| 272 |
+
|
| 273 |
+
Returns:
|
| 274 |
+
A list with one element for each chain copy that should be generated.
|
| 275 |
+
Each element is a list of transform ids to apply.
|
| 276 |
+
"""
|
| 277 |
+
# Expand ranges, e.g. 1-4 -> 1,2,3,4.
|
| 278 |
+
def range_expander(match):
|
| 279 |
+
return ','.join(
|
| 280 |
+
[str(i) for i in range(int(match.group(1)),
|
| 281 |
+
int(match.group(2)) + 1)])
|
| 282 |
+
|
| 283 |
+
ranges_expanded = re.sub(r'\b(\d+)-(\d+)', range_expander, oper_expression)
|
| 284 |
+
|
| 285 |
+
if re.fullmatch(r'(\w+,)*\w+', ranges_expanded):
|
| 286 |
+
# No brackets, just a single range, e.g. "1,2,3".
|
| 287 |
+
return [(t,) for t in ranges_expanded.split(',')]
|
| 288 |
+
elif re.fullmatch(r'\((\w+,)*\w+\)', ranges_expanded):
|
| 289 |
+
# Single range in brackets, e.g. "(1,2,3)".
|
| 290 |
+
return [(t,) for t in ranges_expanded[1:-1].split(',')]
|
| 291 |
+
elif re.fullmatch(r'\((\w+,)*\w+\)\((\w+,)*\w+\)', ranges_expanded):
|
| 292 |
+
# Cartesian product of two ranges, e.g. "(1,2,3)(4,5)".
|
| 293 |
+
part1, part2 = ranges_expanded[1:-1].split(')(')
|
| 294 |
+
return list(itertools.product(part1.split(','), part2.split(',')))
|
| 295 |
+
else:
|
| 296 |
+
raise ValueError(f'Unsupported oper_expression format: {oper_expression}')
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
def format_float_array(
|
| 300 |
+
values: np.ndarray, num_decimal_places: int) -> Sequence[str]:
|
| 301 |
+
"""Converts 1D array to a list of strings with the given number of decimals.
|
| 302 |
+
|
| 303 |
+
This function is faster than converting via Python list comprehension, e.g.:
|
| 304 |
+
atoms_x = ['%.3f' % x for x in atoms_x]
|
| 305 |
+
|
| 306 |
+
Args:
|
| 307 |
+
values: A numpy array with values to convert. This array is casted to
|
| 308 |
+
float32 before doing the conversion.
|
| 309 |
+
num_decimal_places: The number of decimal points to keep, including trailing
|
| 310 |
+
zeros. E.g. for 1.07 and num_decimal_places=1: 1.1,
|
| 311 |
+
num_decimal_places=2: 1.07, num_decimal_places=3: 1.070.
|
| 312 |
+
|
| 313 |
+
Returns:
|
| 314 |
+
A list of formatted strings.
|
| 315 |
+
"""
|
| 316 |
+
if values.ndim != 1:
|
| 317 |
+
raise ValueError(f'The given array must be 1D, got {values.ndim}D')
|
| 318 |
+
|
| 319 |
+
return string_array.format_float_array(
|
| 320 |
+
values=values.astype(np.float32), num_decimal_places=num_decimal_places
|
| 321 |
+
)
|
flax_model/alphafold3/structure/parsing.py
ADDED
|
@@ -0,0 +1,1801 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
"""Module for parsing various data sources and producing Structures."""
|
| 4 |
+
|
| 5 |
+
from collections.abc import Collection, Mapping, MutableMapping, Sequence
|
| 6 |
+
import dataclasses
|
| 7 |
+
import datetime
|
| 8 |
+
import enum
|
| 9 |
+
import functools
|
| 10 |
+
import itertools
|
| 11 |
+
from typing import TypeAlias
|
| 12 |
+
|
| 13 |
+
from flax_model.alphafold3.constants import chemical_components
|
| 14 |
+
from flax_model.alphafold3.constants import mmcif_names
|
| 15 |
+
from flax_model.alphafold3.constants import residue_names
|
| 16 |
+
from flax_model.alphafold3.cpp import mmcif_utils
|
| 17 |
+
from flax_model.alphafold3.cpp import string_array
|
| 18 |
+
from flax_model.alphafold3.structure import bioassemblies
|
| 19 |
+
from flax_model.alphafold3.structure import bonds
|
| 20 |
+
from flax_model.alphafold3.structure import chemical_components as struc_chem_comps
|
| 21 |
+
from flax_model.alphafold3.structure import mmcif
|
| 22 |
+
from flax_model.alphafold3.structure import structure
|
| 23 |
+
from flax_model.alphafold3.structure import structure_tables
|
| 24 |
+
import numpy as np
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
ChainIndex: TypeAlias = int
|
| 28 |
+
ResIndex: TypeAlias = int
|
| 29 |
+
AtomName: TypeAlias = str
|
| 30 |
+
BondAtomId: TypeAlias = tuple[ChainIndex, ResIndex, AtomName]
|
| 31 |
+
|
| 32 |
+
_INSERTION_CODE_REMAP: Mapping[str, str] = {'.': '?'}
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class NoAtomsError(Exception):
|
| 36 |
+
"""Raise when the mmCIF does not have any atoms."""
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
| 40 |
+
class BondIndices:
|
| 41 |
+
from_indices: list[int]
|
| 42 |
+
dest_indices: list[int]
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
@enum.unique
|
| 46 |
+
class ModelID(enum.Enum):
|
| 47 |
+
"""Values for specifying model IDs when parsing."""
|
| 48 |
+
|
| 49 |
+
FIRST = 1 # The first model in the file.
|
| 50 |
+
ALL = 2 # All models in the file.
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@enum.unique
|
| 54 |
+
class SequenceFormat(enum.Enum):
|
| 55 |
+
"""The possible formats for an input sequence."""
|
| 56 |
+
|
| 57 |
+
FASTA = 'fasta' # One-letter code used in FASTA.
|
| 58 |
+
CCD_CODES = 'ccd_codes' # Multiple-letter chemical components dictionary ids.
|
| 59 |
+
LIGAND_SMILES = 'ligand_smiles' # SMILES string defining a molecule.
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def _create_bond_lookup(
|
| 63 |
+
bonded_atom_pairs: Sequence[tuple[BondAtomId, BondAtomId]],
|
| 64 |
+
) -> Mapping[tuple[ChainIndex, ResIndex], Mapping[AtomName, BondIndices]]:
|
| 65 |
+
"""Creates maps to help find bonds during a loop over residues."""
|
| 66 |
+
bond_lookup = {}
|
| 67 |
+
for bond_i, (from_atom_id, dest_atom_id) in enumerate(bonded_atom_pairs):
|
| 68 |
+
from_chain_i, from_res_i, from_atom_name = from_atom_id
|
| 69 |
+
dest_chain_i, dest_res_i, dest_atom_name = dest_atom_id
|
| 70 |
+
bonds_by_from_atom_name = bond_lookup.setdefault(
|
| 71 |
+
(from_chain_i, from_res_i), {}
|
| 72 |
+
)
|
| 73 |
+
bonds_by_dest_atom_name = bond_lookup.setdefault(
|
| 74 |
+
(dest_chain_i, dest_res_i), {}
|
| 75 |
+
)
|
| 76 |
+
bonds_by_from_atom_name.setdefault(
|
| 77 |
+
from_atom_name, BondIndices(from_indices=[], dest_indices=[])
|
| 78 |
+
).from_indices.append(bond_i)
|
| 79 |
+
bonds_by_dest_atom_name.setdefault(
|
| 80 |
+
dest_atom_name, BondIndices(from_indices=[], dest_indices=[])
|
| 81 |
+
).dest_indices.append(bond_i)
|
| 82 |
+
return bond_lookup
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _get_atom_element(
|
| 86 |
+
ccd: chemical_components.Ccd, res_name: str, atom_name: str
|
| 87 |
+
) -> str:
|
| 88 |
+
type_symbol = chemical_components.type_symbol(
|
| 89 |
+
ccd, res_name=res_name, atom_name=atom_name
|
| 90 |
+
)
|
| 91 |
+
return type_symbol or '?'
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def _get_representative_atom(
|
| 95 |
+
ccd: chemical_components.Ccd,
|
| 96 |
+
res_name: str,
|
| 97 |
+
chain_type: str,
|
| 98 |
+
sequence_format: SequenceFormat,
|
| 99 |
+
) -> tuple[str, str]:
|
| 100 |
+
match sequence_format:
|
| 101 |
+
case SequenceFormat.CCD_CODES:
|
| 102 |
+
atom_name = _get_first_non_leaving_atom(ccd=ccd, res_name=res_name)
|
| 103 |
+
atom_element = _get_atom_element(
|
| 104 |
+
ccd=ccd, res_name=res_name, atom_name=atom_name
|
| 105 |
+
)
|
| 106 |
+
return atom_name, atom_element
|
| 107 |
+
case SequenceFormat.LIGAND_SMILES:
|
| 108 |
+
return '', '?'
|
| 109 |
+
case SequenceFormat.FASTA:
|
| 110 |
+
if chain_type in mmcif_names.PEPTIDE_CHAIN_TYPES:
|
| 111 |
+
return 'CA', 'C'
|
| 112 |
+
if chain_type in mmcif_names.NUCLEIC_ACID_CHAIN_TYPES:
|
| 113 |
+
return "C1'", 'C'
|
| 114 |
+
else:
|
| 115 |
+
raise ValueError(chain_type)
|
| 116 |
+
case _:
|
| 117 |
+
raise ValueError(sequence_format)
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
@functools.lru_cache(maxsize=128)
|
| 121 |
+
def _get_first_non_leaving_atom(
|
| 122 |
+
ccd: chemical_components.Ccd, res_name: str
|
| 123 |
+
) -> str:
|
| 124 |
+
"""Returns first definitely non-leaving atom if exists, as a stand-in."""
|
| 125 |
+
all_atoms = struc_chem_comps.get_all_atoms_in_entry(ccd, res_name=res_name)[
|
| 126 |
+
'_chem_comp_atom.atom_id'
|
| 127 |
+
]
|
| 128 |
+
representative_atom = all_atoms[0]
|
| 129 |
+
if representative_atom == 'O1' and len(all_atoms) > 1:
|
| 130 |
+
representative_atom = all_atoms[1]
|
| 131 |
+
return representative_atom
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def _add_ligand_to_chem_comp(
|
| 135 |
+
chem_comp: MutableMapping[str, struc_chem_comps.ChemCompEntry],
|
| 136 |
+
ligand_id: str,
|
| 137 |
+
ligand_smiles: str,
|
| 138 |
+
):
|
| 139 |
+
"""Adds a ligand to chemical components. Raises ValueError on mismatch."""
|
| 140 |
+
new_entry = struc_chem_comps.ChemCompEntry(
|
| 141 |
+
type='non-polymer', pdbx_smiles=ligand_smiles
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
existing_entry = chem_comp.get(ligand_id)
|
| 145 |
+
if existing_entry is None:
|
| 146 |
+
chem_comp[ligand_id] = new_entry
|
| 147 |
+
elif existing_entry != new_entry:
|
| 148 |
+
raise ValueError(
|
| 149 |
+
f'Mismatching data for ligand {ligand_id}: '
|
| 150 |
+
f'{new_entry} != {existing_entry}'
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def _get_first_model_id(cif: mmcif.Mmcif) -> str:
|
| 155 |
+
"""Returns cheaply the first model ID from the mmCIF."""
|
| 156 |
+
return cif.get_array(
|
| 157 |
+
'_atom_site.pdbx_PDB_model_num', dtype=object, gather=slice(1)
|
| 158 |
+
)[0]
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
def _get_str_model_id(
|
| 162 |
+
cif: mmcif.Mmcif,
|
| 163 |
+
model_id: ModelID | int,
|
| 164 |
+
) -> str:
|
| 165 |
+
"""Converts a user-specified model_id argument into a string."""
|
| 166 |
+
match model_id:
|
| 167 |
+
case int():
|
| 168 |
+
str_model_id = str(model_id)
|
| 169 |
+
case enum.Enum():
|
| 170 |
+
# We compare the enum's value attribute since regular enum comparison
|
| 171 |
+
# breaks when adhoc importing.
|
| 172 |
+
match model_id.value:
|
| 173 |
+
case ModelID.FIRST.value:
|
| 174 |
+
try:
|
| 175 |
+
str_model_id = _get_first_model_id(cif)
|
| 176 |
+
except IndexError as e:
|
| 177 |
+
raise NoAtomsError(
|
| 178 |
+
'The mmCIF does not have any atoms or'
|
| 179 |
+
' _atom_site.pdbx_PDB_model_num is missing.'
|
| 180 |
+
) from e
|
| 181 |
+
case ModelID.ALL.value:
|
| 182 |
+
str_model_id = ''
|
| 183 |
+
case _:
|
| 184 |
+
raise ValueError(
|
| 185 |
+
f'Model ID {model_id} with value {model_id.value} not recognized.'
|
| 186 |
+
)
|
| 187 |
+
case _:
|
| 188 |
+
raise ValueError(
|
| 189 |
+
f'Model ID {model_id} with type {type(model_id)} not recognized.'
|
| 190 |
+
)
|
| 191 |
+
return str_model_id
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def _parse_bonds(
|
| 195 |
+
cif: mmcif.Mmcif,
|
| 196 |
+
atom_key: np.ndarray,
|
| 197 |
+
model_id: str,
|
| 198 |
+
) -> bonds.Bonds:
|
| 199 |
+
"""Returns the bonds table extracted from the mmCIF.
|
| 200 |
+
|
| 201 |
+
Args:
|
| 202 |
+
cif: The raw mmCIF to extract the bond information from.
|
| 203 |
+
atom_key: A numpy array defining atom key for each atom in _atom_site. Note
|
| 204 |
+
that the atom key must be computed before resolving alt-locs since this
|
| 205 |
+
function operates on the raw mmCIF!
|
| 206 |
+
model_id: The ID of the model to get bonds for.
|
| 207 |
+
"""
|
| 208 |
+
if '_struct_conn.id' not in cif:
|
| 209 |
+
# This is the category key item for the _struct_conn table, therefore
|
| 210 |
+
# we use it to determine whether to parse bond info.
|
| 211 |
+
return bonds.Bonds.make_empty()
|
| 212 |
+
from_atom, dest_atom = mmcif.get_bond_atom_indices(cif, model_id)
|
| 213 |
+
from_atom = np.array(from_atom, dtype=np.int64)
|
| 214 |
+
dest_atom = np.array(dest_atom, dtype=np.int64)
|
| 215 |
+
num_bonds = from_atom.shape[0]
|
| 216 |
+
bond_key = np.arange(num_bonds, dtype=np.int64)
|
| 217 |
+
bond_type = cif.get_array('_struct_conn.conn_type_id', dtype=object)
|
| 218 |
+
if '_struct_conn.pdbx_role' in cif: # This column isn't always present.
|
| 219 |
+
bond_role = cif.get_array('_struct_conn.pdbx_role', dtype=object)
|
| 220 |
+
else:
|
| 221 |
+
bond_role = np.full((num_bonds,), '?', dtype=object)
|
| 222 |
+
|
| 223 |
+
bonds_mask = np.ones((num_bonds,), dtype=bool)
|
| 224 |
+
# Symmetries other than 1_555 imply the atom is not part of the asymmetric
|
| 225 |
+
# unit, and therefore this is a bond that only exists in the expanded
|
| 226 |
+
# bioassembly.
|
| 227 |
+
# We do not currently support parsing these types of bonds.
|
| 228 |
+
if '_struct_conn.ptnr1_symmetry' in cif:
|
| 229 |
+
ptnr1_symmetry = cif.get_array('_struct_conn.ptnr1_symmetry', dtype=object)
|
| 230 |
+
np.logical_and(bonds_mask, ptnr1_symmetry == '1_555', out=bonds_mask)
|
| 231 |
+
if '_struct_conn.ptnr2_symmetry' in cif:
|
| 232 |
+
ptnr2_symmetry = cif.get_array('_struct_conn.ptnr2_symmetry', dtype=object)
|
| 233 |
+
np.logical_and(bonds_mask, ptnr2_symmetry == '1_555', out=bonds_mask)
|
| 234 |
+
# Remove bonds that involve atoms that are not part of the structure,
|
| 235 |
+
# e.g. waters if include_water=False. In a rare case this also removes invalid
|
| 236 |
+
# bonds that are indicated by a key that is set to _atom_site size.
|
| 237 |
+
np.logical_and(bonds_mask, np.isin(from_atom, atom_key), out=bonds_mask)
|
| 238 |
+
np.logical_and(bonds_mask, np.isin(dest_atom, atom_key), out=bonds_mask)
|
| 239 |
+
return bonds.Bonds(
|
| 240 |
+
key=bond_key[bonds_mask],
|
| 241 |
+
type=bond_type[bonds_mask],
|
| 242 |
+
role=bond_role[bonds_mask],
|
| 243 |
+
from_atom_key=from_atom[bonds_mask],
|
| 244 |
+
dest_atom_key=dest_atom[bonds_mask],
|
| 245 |
+
)
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
@dataclasses.dataclass(frozen=True, slots=True)
|
| 249 |
+
class _MmcifHeader:
|
| 250 |
+
name: str
|
| 251 |
+
resolution: float | None
|
| 252 |
+
release_date: datetime.date | None
|
| 253 |
+
structure_method: str | None
|
| 254 |
+
bioassembly_data: bioassemblies.BioassemblyData | None
|
| 255 |
+
chemical_components_data: struc_chem_comps.ChemicalComponentsData | None
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def _get_mmcif_header(
|
| 259 |
+
cif: mmcif.Mmcif,
|
| 260 |
+
fix_mse: bool,
|
| 261 |
+
fix_unknown_dna: bool,
|
| 262 |
+
) -> _MmcifHeader:
|
| 263 |
+
"""Extract header fields from an mmCIF object."""
|
| 264 |
+
entry_id = cif.get('_entry.id')
|
| 265 |
+
name = entry_id[0] if entry_id else cif.get_data_name()
|
| 266 |
+
resolution = mmcif.get_resolution(cif)
|
| 267 |
+
|
| 268 |
+
release_date = mmcif.get_release_date(cif)
|
| 269 |
+
if release_date is not None:
|
| 270 |
+
release_date = datetime.date.fromisoformat(release_date)
|
| 271 |
+
|
| 272 |
+
experiments = cif.get('_exptl.method')
|
| 273 |
+
structure_method = ','.join(experiments) if experiments else None
|
| 274 |
+
|
| 275 |
+
try:
|
| 276 |
+
bioassembly_data = bioassemblies.BioassemblyData.from_mmcif(cif)
|
| 277 |
+
except bioassemblies.MissingBioassemblyDataError:
|
| 278 |
+
bioassembly_data = None
|
| 279 |
+
|
| 280 |
+
try:
|
| 281 |
+
chemical_components_data = (
|
| 282 |
+
struc_chem_comps.ChemicalComponentsData.from_mmcif(
|
| 283 |
+
cif, fix_mse=fix_mse, fix_unknown_dna=fix_unknown_dna
|
| 284 |
+
)
|
| 285 |
+
)
|
| 286 |
+
except struc_chem_comps.MissingChemicalComponentsDataError:
|
| 287 |
+
chemical_components_data = None
|
| 288 |
+
|
| 289 |
+
return _MmcifHeader(
|
| 290 |
+
name=name,
|
| 291 |
+
resolution=resolution,
|
| 292 |
+
release_date=release_date,
|
| 293 |
+
structure_method=structure_method,
|
| 294 |
+
bioassembly_data=bioassembly_data,
|
| 295 |
+
chemical_components_data=chemical_components_data,
|
| 296 |
+
)
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
def from_parsed_mmcif(
|
| 300 |
+
mmcif_object: mmcif.Mmcif,
|
| 301 |
+
*,
|
| 302 |
+
name: str | None = None,
|
| 303 |
+
fix_mse_residues: bool = False,
|
| 304 |
+
fix_arginines: bool = False,
|
| 305 |
+
fix_unknown_dna: bool = False,
|
| 306 |
+
include_water: bool = False,
|
| 307 |
+
include_other: bool = False,
|
| 308 |
+
include_bonds: bool = False,
|
| 309 |
+
model_id: int | ModelID = ModelID.FIRST,
|
| 310 |
+
) -> structure.Structure:
|
| 311 |
+
"""Construct a Structure from a parsed mmCIF object.
|
| 312 |
+
|
| 313 |
+
This function is called by `from_mmcif` but can be useful when an mmCIF has
|
| 314 |
+
already been parsed e.g. to extract extra information from the header before
|
| 315 |
+
then converting to Structure for further manipulation.
|
| 316 |
+
|
| 317 |
+
Args:
|
| 318 |
+
mmcif_object: A parsed mmcif.Mmcif object.
|
| 319 |
+
name: Optional name for the structure. If not provided, the name will be
|
| 320 |
+
taken from the mmCIF data_ field.
|
| 321 |
+
fix_mse_residues: If True, selenium atom sites (SE) in selenomethionine
|
| 322 |
+
(MSE) residues will be changed to sulphur atom sites (SD). This is because
|
| 323 |
+
methionine (MET) residues are often replaced with MSE to aid X-Ray
|
| 324 |
+
crystallography. If False, the SE MSE atom sites won't be modified.
|
| 325 |
+
fix_arginines: If True, NH1 and NH2 in arginine will be swapped if needed so
|
| 326 |
+
that NH1 is always closer to CD than NH2. If False, no atom sites in
|
| 327 |
+
arginine will be touched. Note that HH11, HH12, HH21, HH22 are fixed too.
|
| 328 |
+
fix_unknown_dna: If True, residues with name N in DNA chains will have their
|
| 329 |
+
res_name replaced with DN. Atoms are not changed.
|
| 330 |
+
include_water: If True, water (HOH) molecules will be parsed. Water
|
| 331 |
+
molecules may be grouped into chains, where number of residues > 1. Water
|
| 332 |
+
molecules are usually grouped into chains but do not necessarily all share
|
| 333 |
+
the same chain ID.
|
| 334 |
+
include_other: If True, all other atoms that are not included by any of the
|
| 335 |
+
above parameters will be included. This covers e.g. "polypeptide(D)" and
|
| 336 |
+
"macrolide" entities, as well as all other non-standard types.
|
| 337 |
+
include_bonds: If True, bond information will be parsed from the mmCIF and
|
| 338 |
+
stored in the Structure.
|
| 339 |
+
model_id: Either the integer model ID to parse, or one of ModelID.FIRST to
|
| 340 |
+
parse the first model, or ModelID.ALL to parse all models.
|
| 341 |
+
|
| 342 |
+
Returns:
|
| 343 |
+
A Structure representation of the mmCIF object.
|
| 344 |
+
"""
|
| 345 |
+
str_model_id = _get_str_model_id(cif=mmcif_object, model_id=model_id)
|
| 346 |
+
header = _get_mmcif_header(
|
| 347 |
+
mmcif_object, fix_mse=fix_mse_residues, fix_unknown_dna=fix_unknown_dna
|
| 348 |
+
)
|
| 349 |
+
|
| 350 |
+
chains, residues, atoms = get_tables(
|
| 351 |
+
cif=mmcif_object,
|
| 352 |
+
fix_mse_residues=fix_mse_residues,
|
| 353 |
+
fix_arginines=fix_arginines,
|
| 354 |
+
fix_unknown_dna=fix_unknown_dna,
|
| 355 |
+
include_water=include_water,
|
| 356 |
+
include_other=include_other,
|
| 357 |
+
model_id=str_model_id,
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
if include_bonds and atoms.size > 0:
|
| 361 |
+
# NB: parsing the atom table before the bonds table allows for a more
|
| 362 |
+
# informative error message when dealing with bad multi-model mmCIFs.
|
| 363 |
+
# Also always use a specific model ID, even when parsing all models.
|
| 364 |
+
if str_model_id == '': # pylint: disable=g-explicit-bool-comparison
|
| 365 |
+
bonds_model_id = _get_first_model_id(mmcif_object)
|
| 366 |
+
else:
|
| 367 |
+
bonds_model_id = str_model_id
|
| 368 |
+
|
| 369 |
+
bonds_table = _parse_bonds(
|
| 370 |
+
mmcif_object,
|
| 371 |
+
atom_key=atoms.key,
|
| 372 |
+
model_id=bonds_model_id,
|
| 373 |
+
)
|
| 374 |
+
else:
|
| 375 |
+
bonds_table = bonds.Bonds.make_empty()
|
| 376 |
+
|
| 377 |
+
return structure.Structure(
|
| 378 |
+
name=name if name is not None else header.name,
|
| 379 |
+
resolution=header.resolution,
|
| 380 |
+
release_date=header.release_date,
|
| 381 |
+
structure_method=header.structure_method,
|
| 382 |
+
bioassembly_data=header.bioassembly_data,
|
| 383 |
+
chemical_components_data=header.chemical_components_data,
|
| 384 |
+
bonds=bonds_table,
|
| 385 |
+
chains=chains,
|
| 386 |
+
residues=residues,
|
| 387 |
+
atoms=atoms,
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
def from_mmcif(
|
| 392 |
+
mmcif_string: str | bytes,
|
| 393 |
+
*,
|
| 394 |
+
name: str | None = None,
|
| 395 |
+
fix_mse_residues: bool = False,
|
| 396 |
+
fix_arginines: bool = False,
|
| 397 |
+
fix_unknown_dna: bool = False,
|
| 398 |
+
include_water: bool = False,
|
| 399 |
+
include_other: bool = False,
|
| 400 |
+
include_bonds: bool = False,
|
| 401 |
+
model_id: int | ModelID = ModelID.FIRST,
|
| 402 |
+
) -> structure.Structure:
|
| 403 |
+
"""Construct a Structure from a mmCIF string.
|
| 404 |
+
|
| 405 |
+
Args:
|
| 406 |
+
mmcif_string: The string contents of an mmCIF file.
|
| 407 |
+
name: Optional name for the structure. If not provided, the name will be
|
| 408 |
+
taken from the mmCIF data_ field.
|
| 409 |
+
fix_mse_residues: If True, selenium atom sites (SE) in selenomethionine
|
| 410 |
+
(MSE) residues will be changed to sulphur atom sites (SD). This is because
|
| 411 |
+
methionine (MET) residues are often replaced with MSE to aid X-Ray
|
| 412 |
+
crystallography. If False, the SE MSE atom sites won't be modified.
|
| 413 |
+
fix_arginines: If True, NH1 and NH2 in arginine will be swapped if needed so
|
| 414 |
+
that NH1 is always closer to CD than NH2. If False, no atom sites in
|
| 415 |
+
arginine will be touched. Note that HH11, HH12, HH21, HH22 are fixed too.
|
| 416 |
+
fix_unknown_dna: If True, residues with name N in DNA chains will have their
|
| 417 |
+
res_name replaced with DN. Atoms are not changed.
|
| 418 |
+
include_water: If True, water (HOH) molecules will be parsed. Water
|
| 419 |
+
molecules may be grouped into chains, where number of residues > 1. Water
|
| 420 |
+
molecules are usually grouped into chains but do not necessarily all share
|
| 421 |
+
the same chain ID.
|
| 422 |
+
include_other: If True, all other atoms that are not included by any of the
|
| 423 |
+
above parameters will be included. This covers e.g. "polypeptide(D)" and
|
| 424 |
+
"macrolide" entities, as well as all other non-standard types.
|
| 425 |
+
include_bonds: If True, bond information will be parsed from the mmCIF and
|
| 426 |
+
stored in the Structure.
|
| 427 |
+
model_id: Either the integer model ID to parse, or one of ModelID.FIRST to
|
| 428 |
+
parse the first model, or ModelID.ALL to parse all models.
|
| 429 |
+
|
| 430 |
+
Returns:
|
| 431 |
+
A Structure representation of the mmCIF string.
|
| 432 |
+
"""
|
| 433 |
+
mmcif_object = mmcif.from_string(mmcif_string)
|
| 434 |
+
|
| 435 |
+
return from_parsed_mmcif(
|
| 436 |
+
mmcif_object,
|
| 437 |
+
name=name,
|
| 438 |
+
fix_mse_residues=fix_mse_residues,
|
| 439 |
+
fix_arginines=fix_arginines,
|
| 440 |
+
fix_unknown_dna=fix_unknown_dna,
|
| 441 |
+
include_water=include_water,
|
| 442 |
+
include_other=include_other,
|
| 443 |
+
include_bonds=include_bonds,
|
| 444 |
+
model_id=model_id,
|
| 445 |
+
)
|
| 446 |
+
|
| 447 |
+
|
| 448 |
+
def from_res_arrays(atom_mask: np.ndarray, **kwargs) -> structure.Structure:
|
| 449 |
+
"""Returns Structure created from from arrays with a residue dimension.
|
| 450 |
+
|
| 451 |
+
All unset fields are filled with defaults (e.g. 1.0 for occupancy) or
|
| 452 |
+
unset/unknown values (e.g. UNK for residue type, or '.' for atom element).
|
| 453 |
+
|
| 454 |
+
Args:
|
| 455 |
+
atom_mask: A array with shape (num_res, num_atom). This is used to decide
|
| 456 |
+
which atoms in the atom dimension are present in a given residue. Present
|
| 457 |
+
atoms should have a nonzero value, e.g. 1.0 or True.
|
| 458 |
+
**kwargs: A mapping from field name to values. For all array-valued fields
|
| 459 |
+
these arrays must have a dimension of length num_res. Chain and residue
|
| 460 |
+
fields should have this as their only dimension and atom fields should be
|
| 461 |
+
shaped (num_res, num_atom). Coordinate fields may also have arbitrary
|
| 462 |
+
leading dimensions (they must be the same across all coordinate fields).
|
| 463 |
+
See structure.{CHAIN,RESIDUE,ATOM}_FIELDS for a list of allowed fields.
|
| 464 |
+
"""
|
| 465 |
+
num_res, num_atom = atom_mask.shape
|
| 466 |
+
included_indices = np.flatnonzero(atom_mask)
|
| 467 |
+
|
| 468 |
+
array_fields = (
|
| 469 |
+
structure.CHAIN_FIELDS.keys()
|
| 470 |
+
| structure.RESIDUE_FIELDS.keys()
|
| 471 |
+
| structure.ATOM_FIELDS.keys()
|
| 472 |
+
)
|
| 473 |
+
initializer_kwargs = {}
|
| 474 |
+
fields = {}
|
| 475 |
+
for k, val in kwargs.items():
|
| 476 |
+
if k not in array_fields:
|
| 477 |
+
# The kwarg key isn't an array field name. Such kwargs are forwarded as-is
|
| 478 |
+
# to the constructor. They are expected to be global fields (e.g. name).
|
| 479 |
+
# Other values will raise an error when the constructor is called.
|
| 480 |
+
if k in structure.TABLE_FIELDS:
|
| 481 |
+
raise ValueError(f'Table fields must not be set. Got {k}.')
|
| 482 |
+
initializer_kwargs[k] = val
|
| 483 |
+
continue
|
| 484 |
+
elif val is None:
|
| 485 |
+
raise ValueError(f'{k} must be non-None.')
|
| 486 |
+
|
| 487 |
+
if not isinstance(val, np.ndarray):
|
| 488 |
+
raise TypeError(f'Value for {k} must be a NumPy array. Got {type(val)}.')
|
| 489 |
+
if k in structure.CHAIN_FIELDS or k in structure.RESIDUE_FIELDS:
|
| 490 |
+
if val.shape != (num_res,):
|
| 491 |
+
raise ValueError(
|
| 492 |
+
f'{k} must have shape ({num_res=},). Got {val.shape=}.'
|
| 493 |
+
)
|
| 494 |
+
# Do not reshape the chain/residue arrays, they have the shape we need.
|
| 495 |
+
fields[k] = val
|
| 496 |
+
else:
|
| 497 |
+
assert k in structure.ATOM_FIELDS
|
| 498 |
+
if val.shape[-2:] != (num_res, num_atom):
|
| 499 |
+
raise ValueError(
|
| 500 |
+
f'{k} must have final two dimensions of length '
|
| 501 |
+
f'{(num_res, num_atom)=}. Got {val.shape=}.'
|
| 502 |
+
)
|
| 503 |
+
leading_dims = val.shape[:-2]
|
| 504 |
+
flat_val = val.reshape(leading_dims + (-1,), order='C')
|
| 505 |
+
masked_val = flat_val[..., included_indices]
|
| 506 |
+
fields[k] = masked_val
|
| 507 |
+
|
| 508 |
+
# Get chain IDs or assume this is a single-chain structure.
|
| 509 |
+
chain_id = kwargs.get('chain_id', np.array(['A'] * num_res, dtype=object))
|
| 510 |
+
# Find chain starts in res-sized arrays, use these to make chain-sized arrays.
|
| 511 |
+
chain_start = np.concatenate(
|
| 512 |
+
([0], np.where(chain_id[1:] != chain_id[:-1])[0] + 1)
|
| 513 |
+
)
|
| 514 |
+
if len(set(chain_id)) != len(chain_start):
|
| 515 |
+
raise ValueError(f'Chain IDs must be contiguous, but got {chain_id}')
|
| 516 |
+
|
| 517 |
+
chain_lengths = np.diff(chain_start, append=len(chain_id))
|
| 518 |
+
chain_key = np.repeat(np.arange(len(chain_start)), chain_lengths)
|
| 519 |
+
|
| 520 |
+
chain_entity_id = fields.get('chain_entity_id')
|
| 521 |
+
if chain_entity_id is not None:
|
| 522 |
+
entity_id = chain_entity_id[chain_start]
|
| 523 |
+
else:
|
| 524 |
+
entity_id = np.array(
|
| 525 |
+
[str(mmcif.str_id_to_int_id(cid)) for cid in chain_id[chain_start]],
|
| 526 |
+
dtype=object,
|
| 527 |
+
)
|
| 528 |
+
chain_str_empty = np.full((num_res,), '.', dtype=object)
|
| 529 |
+
chains_table = structure_tables.Chains(
|
| 530 |
+
key=chain_key[chain_start],
|
| 531 |
+
id=chain_id[chain_start],
|
| 532 |
+
type=fields.get('chain_type', chain_str_empty)[chain_start],
|
| 533 |
+
auth_asym_id=fields.get('chain_auth_asym_id', chain_id)[chain_start],
|
| 534 |
+
entity_id=entity_id,
|
| 535 |
+
entity_desc=fields.get('chain_entity_desc', chain_str_empty)[chain_start],
|
| 536 |
+
)
|
| 537 |
+
|
| 538 |
+
# Since all arrays are residue-shaped, we can use them directly.
|
| 539 |
+
res_key = np.arange(num_res, dtype=np.int64)
|
| 540 |
+
res_id = fields.get('res_id', res_key + 1).astype(np.int32)
|
| 541 |
+
residues_table = structure_tables.Residues(
|
| 542 |
+
key=res_key,
|
| 543 |
+
chain_key=chain_key,
|
| 544 |
+
id=res_id,
|
| 545 |
+
name=fields.get('res_name', np.full(num_res, 'UNK', dtype=object)),
|
| 546 |
+
auth_seq_id=fields.get(
|
| 547 |
+
'res_auth_seq_id', np.char.mod('%d', res_id).astype(object)
|
| 548 |
+
),
|
| 549 |
+
insertion_code=fields.get(
|
| 550 |
+
'res_insertion_code', np.full(num_res, '?', dtype=object)
|
| 551 |
+
),
|
| 552 |
+
)
|
| 553 |
+
|
| 554 |
+
# The atom-sized arrays have already been masked and reshaped.
|
| 555 |
+
num_atoms_per_res = np.sum(atom_mask, axis=1, dtype=np.int32)
|
| 556 |
+
num_atoms_total = np.sum(num_atoms_per_res, dtype=np.int32)
|
| 557 |
+
# Structure is immutable, so use the same array multiple times to save RAM.
|
| 558 |
+
atom_str_empty = np.full(num_atoms_total, '.', dtype=object)
|
| 559 |
+
atom_float32_zeros = np.zeros(num_atoms_total, dtype=np.float32)
|
| 560 |
+
atom_float32_ones = np.ones(num_atoms_total, dtype=np.float32)
|
| 561 |
+
atoms_table = structure_tables.Atoms(
|
| 562 |
+
key=np.arange(num_atoms_total, dtype=np.int64),
|
| 563 |
+
chain_key=np.repeat(chain_key, num_atoms_per_res),
|
| 564 |
+
res_key=np.repeat(res_key, num_atoms_per_res),
|
| 565 |
+
name=fields.get('atom_name', atom_str_empty),
|
| 566 |
+
element=fields.get('atom_element', atom_str_empty),
|
| 567 |
+
x=fields.get('atom_x', atom_float32_zeros),
|
| 568 |
+
y=fields.get('atom_y', atom_float32_zeros),
|
| 569 |
+
z=fields.get('atom_z', atom_float32_zeros),
|
| 570 |
+
b_factor=fields.get('atom_b_factor', atom_float32_zeros),
|
| 571 |
+
occupancy=fields.get('atom_occupancy', atom_float32_ones),
|
| 572 |
+
)
|
| 573 |
+
|
| 574 |
+
return structure.Structure(
|
| 575 |
+
chains=chains_table,
|
| 576 |
+
residues=residues_table,
|
| 577 |
+
atoms=atoms_table,
|
| 578 |
+
bonds=structure_tables.Bonds.make_empty(), # Currently not set.
|
| 579 |
+
**initializer_kwargs,
|
| 580 |
+
)
|
| 581 |
+
|
| 582 |
+
|
| 583 |
+
def expand_sequence(
|
| 584 |
+
sequence: str, chain_type: str, sequence_format: SequenceFormat
|
| 585 |
+
) -> Sequence[str]:
|
| 586 |
+
"""Returns full residue names based on a sequence string.
|
| 587 |
+
|
| 588 |
+
Args:
|
| 589 |
+
sequence: A string representing the sequence.
|
| 590 |
+
chain_type: The chain type of the sequence.
|
| 591 |
+
sequence_format: The format of the sequence argument.
|
| 592 |
+
"""
|
| 593 |
+
match sequence_format:
|
| 594 |
+
case SequenceFormat.FASTA:
|
| 595 |
+
if not all(c.isalpha() for c in sequence):
|
| 596 |
+
raise ValueError(f'Sequence "{sequence}" has non-alphabetic characters')
|
| 597 |
+
match chain_type:
|
| 598 |
+
case mmcif_names.PROTEIN_CHAIN:
|
| 599 |
+
res_name_map = residue_names.PROTEIN_COMMON_ONE_TO_THREE
|
| 600 |
+
default_res_name = residue_names.UNK
|
| 601 |
+
case mmcif_names.RNA_CHAIN:
|
| 602 |
+
res_name_map = {r: r for r in residue_names.RNA_TYPES}
|
| 603 |
+
default_res_name = residue_names.UNK_RNA
|
| 604 |
+
case mmcif_names.DNA_CHAIN:
|
| 605 |
+
res_name_map = residue_names.DNA_COMMON_ONE_TO_TWO
|
| 606 |
+
default_res_name = residue_names.UNK_DNA
|
| 607 |
+
case _:
|
| 608 |
+
raise ValueError(f'{chain_type=} not supported for FASTA format.')
|
| 609 |
+
return [
|
| 610 |
+
res_name_map.get(one_letter_res, default_res_name)
|
| 611 |
+
for one_letter_res in sequence
|
| 612 |
+
]
|
| 613 |
+
case SequenceFormat.CCD_CODES:
|
| 614 |
+
return sequence.strip('()').split(')(')
|
| 615 |
+
case SequenceFormat.LIGAND_SMILES:
|
| 616 |
+
ligand_id, _ = sequence.split(':', maxsplit=1)
|
| 617 |
+
return [ligand_id]
|
| 618 |
+
|
| 619 |
+
|
| 620 |
+
def from_sequences_and_bonds(
|
| 621 |
+
*,
|
| 622 |
+
sequences: Sequence[str],
|
| 623 |
+
chain_types: Sequence[str],
|
| 624 |
+
sequence_formats: Sequence[SequenceFormat],
|
| 625 |
+
bonded_atom_pairs: Sequence[tuple[BondAtomId, BondAtomId]] | None,
|
| 626 |
+
ccd: chemical_components.Ccd,
|
| 627 |
+
chain_ids: Sequence[str] | None = None,
|
| 628 |
+
name: str = 'from_sequences_and_bonds',
|
| 629 |
+
bond_type: str | None = None,
|
| 630 |
+
**constructor_args,
|
| 631 |
+
) -> structure.Structure:
|
| 632 |
+
"""Returns a minimal structure for the input sequences and bonds.
|
| 633 |
+
|
| 634 |
+
The returned structure will have at least one atom per residue. If the
|
| 635 |
+
residue has any bonded atoms, according to `bonded_atom_pairs`, then
|
| 636 |
+
all (and only) those atoms will be present for that residue. If the residue
|
| 637 |
+
is not involved in any bond then an arbitrary atom will be created.
|
| 638 |
+
|
| 639 |
+
Args:
|
| 640 |
+
sequences: A sequence of strings, each one representing a single chain.
|
| 641 |
+
chain_types: The types of each chain, e.g. polypeptide(L). The n-th element
|
| 642 |
+
describes the n-th sequence in `sequences`.
|
| 643 |
+
sequence_formats: The format of each sequence. The n-th element describes
|
| 644 |
+
the n-th sequence in `sequences`.
|
| 645 |
+
bonded_atom_pairs: A sequence of bonded atom pairs. Each atom is described
|
| 646 |
+
as a tuple of (chain_index, res_index, atom_name), where the first two
|
| 647 |
+
values are 0-based indices. The chain_index is the index of the chain in
|
| 648 |
+
the `sequences` argument, and the res_index is the index of the residue in
|
| 649 |
+
that sequence. The atom_name is the name of the atom in the residue, e.g.
|
| 650 |
+
CA. If the atom is not found in the standard atoms for that residue
|
| 651 |
+
(according to the CCD) then an error is raised.
|
| 652 |
+
ccd: The chemical components dictionary.
|
| 653 |
+
chain_ids: A sequence of chain IDs, one for each chain in `sequences`. If
|
| 654 |
+
not provided, then the chain IDs will be generated automatically based on
|
| 655 |
+
sequence indices.
|
| 656 |
+
name: A name for the returned structure.
|
| 657 |
+
bond_type: This type will be used for all bonds in the structure, where type
|
| 658 |
+
follows PDB scheme, e.g. unknown (?), hydrog, metalc, covale, disulf.
|
| 659 |
+
**constructor_args: These arguments are passed directly to the
|
| 660 |
+
structure.Structure constructor.
|
| 661 |
+
"""
|
| 662 |
+
chain_id = []
|
| 663 |
+
chain_type = []
|
| 664 |
+
chain_res_count = []
|
| 665 |
+
res_id = []
|
| 666 |
+
res_name = []
|
| 667 |
+
res_atom_count = []
|
| 668 |
+
atom_name = []
|
| 669 |
+
atom_element = []
|
| 670 |
+
chem_comp = {}
|
| 671 |
+
|
| 672 |
+
num_bonds = len(bonded_atom_pairs or ())
|
| 673 |
+
from_atom_key = np.full((num_bonds,), -1, dtype=np.int64)
|
| 674 |
+
dest_atom_key = np.full((num_bonds,), -1, dtype=np.int64)
|
| 675 |
+
|
| 676 |
+
# Create map (chain_i, res_i) -> {atom_name -> (from_idxs dest_idxs)}.
|
| 677 |
+
# This allows quick lookup of whether a residue has any bonded atoms, and
|
| 678 |
+
# which bonds those atoms participate in.
|
| 679 |
+
bond_lookup = _create_bond_lookup(bonded_atom_pairs or ())
|
| 680 |
+
|
| 681 |
+
current_atom_key = 0
|
| 682 |
+
for chain_i, (sequence, curr_chain_type, sequence_format) in enumerate(
|
| 683 |
+
zip(sequences, chain_types, sequence_formats, strict=True)
|
| 684 |
+
):
|
| 685 |
+
if chain_ids is not None:
|
| 686 |
+
current_chain_id = chain_ids[chain_i]
|
| 687 |
+
else:
|
| 688 |
+
current_chain_id = mmcif.int_id_to_str_id(chain_i + 1)
|
| 689 |
+
num_chain_residues = 0
|
| 690 |
+
for res_i, full_res_name in enumerate(
|
| 691 |
+
expand_sequence(sequence, curr_chain_type, sequence_format)
|
| 692 |
+
):
|
| 693 |
+
current_res_id = res_i + 1
|
| 694 |
+
num_res_atoms = 0
|
| 695 |
+
|
| 696 |
+
# Look for bonded atoms in the bond lookup and if any are found, add
|
| 697 |
+
# their atom keys to the bond atom_key columns.
|
| 698 |
+
if bond_indices_by_atom_name := bond_lookup.get((chain_i, res_i)):
|
| 699 |
+
comp_atoms = None
|
| 700 |
+
if sequence_format != SequenceFormat.LIGAND_SMILES:
|
| 701 |
+
comp_atoms = set(ccd.get(full_res_name)['_chem_comp_atom.atom_id'])
|
| 702 |
+
for bond_atom_name, bond_indices in bond_indices_by_atom_name.items():
|
| 703 |
+
if comp_atoms is not None and bond_atom_name not in comp_atoms:
|
| 704 |
+
raise ValueError(
|
| 705 |
+
f'Bonded atom "{bond_atom_name}" was not found in the list of'
|
| 706 |
+
f' atoms of the chemical component {full_res_name}. Valid atom'
|
| 707 |
+
f' names for {full_res_name} are: {sorted(comp_atoms)}.'
|
| 708 |
+
' This is likely caused by an invalid atom name in the bonded'
|
| 709 |
+
f' atom (chain_id={current_chain_id}, res_id={current_res_id},'
|
| 710 |
+
f' atom_name={bond_atom_name}) specified in `bondedAtomPairs`'
|
| 711 |
+
' in the input JSON.'
|
| 712 |
+
)
|
| 713 |
+
atom_name.append(bond_atom_name)
|
| 714 |
+
atom_element.append(
|
| 715 |
+
_get_atom_element(
|
| 716 |
+
ccd=ccd, res_name=full_res_name, atom_name=bond_atom_name
|
| 717 |
+
)
|
| 718 |
+
)
|
| 719 |
+
for from_bond_i in bond_indices.from_indices:
|
| 720 |
+
from_atom_key[from_bond_i] = current_atom_key
|
| 721 |
+
for dest_bond_i in bond_indices.dest_indices:
|
| 722 |
+
dest_atom_key[dest_bond_i] = current_atom_key
|
| 723 |
+
current_atom_key += 1
|
| 724 |
+
num_res_atoms += 1
|
| 725 |
+
else:
|
| 726 |
+
# If this residue has no bonded atoms then we need to add one atom
|
| 727 |
+
# like in from_sequences.
|
| 728 |
+
assert num_res_atoms == 0
|
| 729 |
+
rep_atom_name, rep_atom_element = _get_representative_atom(
|
| 730 |
+
ccd=ccd,
|
| 731 |
+
res_name=full_res_name,
|
| 732 |
+
chain_type=curr_chain_type,
|
| 733 |
+
sequence_format=sequence_format,
|
| 734 |
+
)
|
| 735 |
+
atom_name.append(rep_atom_name)
|
| 736 |
+
atom_element.append(rep_atom_element)
|
| 737 |
+
num_res_atoms += 1
|
| 738 |
+
current_atom_key += 1
|
| 739 |
+
|
| 740 |
+
if sequence_format == SequenceFormat.LIGAND_SMILES:
|
| 741 |
+
# Sequence expect to be in the format <ligand_id>:<ligand_smiles>,
|
| 742 |
+
# which always corresponds to a single-residue chain.
|
| 743 |
+
ligand_id, ligand_smiles = sequence.split(':', maxsplit=1)
|
| 744 |
+
if ccd.get(ligand_id) is not None:
|
| 745 |
+
raise ValueError(
|
| 746 |
+
f'Ligand name {ligand_id} is in CCD - it is not supported to give'
|
| 747 |
+
' ligands created from SMILES the same name as CCD components.'
|
| 748 |
+
)
|
| 749 |
+
# We need to provide additional chemical components metadata for
|
| 750 |
+
# ligands specified via SMILES strings since they might not be in CCD.
|
| 751 |
+
_add_ligand_to_chem_comp(chem_comp, ligand_id, ligand_smiles)
|
| 752 |
+
|
| 753 |
+
assert num_res_atoms >= 1
|
| 754 |
+
res_atom_count.append(num_res_atoms)
|
| 755 |
+
num_chain_residues += 1
|
| 756 |
+
res_id.append(current_res_id)
|
| 757 |
+
res_name.append(full_res_name)
|
| 758 |
+
|
| 759 |
+
chain_id.append(current_chain_id)
|
| 760 |
+
chain_type.append(curr_chain_type)
|
| 761 |
+
chain_res_count.append(num_chain_residues)
|
| 762 |
+
|
| 763 |
+
chem_comp_data = struc_chem_comps.ChemicalComponentsData(chem_comp)
|
| 764 |
+
chem_comp_data = struc_chem_comps.populate_missing_ccd_data(
|
| 765 |
+
ccd=ccd,
|
| 766 |
+
chemical_components_data=chem_comp_data,
|
| 767 |
+
chemical_component_ids=set(res_name),
|
| 768 |
+
)
|
| 769 |
+
|
| 770 |
+
if bonded_atom_pairs is not None:
|
| 771 |
+
unknown_bond_col = np.full((num_bonds,), '?', dtype=object)
|
| 772 |
+
if bond_type is None:
|
| 773 |
+
bond_type_col = unknown_bond_col
|
| 774 |
+
else:
|
| 775 |
+
bond_type_col = np.full((num_bonds,), bond_type, dtype=object)
|
| 776 |
+
bonds_table = bonds.Bonds(
|
| 777 |
+
key=np.arange(num_bonds, dtype=np.int64),
|
| 778 |
+
type=bond_type_col,
|
| 779 |
+
role=unknown_bond_col,
|
| 780 |
+
from_atom_key=from_atom_key,
|
| 781 |
+
dest_atom_key=dest_atom_key,
|
| 782 |
+
)
|
| 783 |
+
else:
|
| 784 |
+
bonds_table = structure_tables.Bonds.make_empty()
|
| 785 |
+
|
| 786 |
+
chain_key = np.arange(len(sequences), dtype=np.int64) # 1 chain per sequence.
|
| 787 |
+
chain_id = np.array(chain_id, dtype=object)
|
| 788 |
+
chains_table = structure_tables.Chains(
|
| 789 |
+
key=chain_key,
|
| 790 |
+
id=chain_id,
|
| 791 |
+
type=np.array(chain_type, dtype=object),
|
| 792 |
+
auth_asym_id=chain_id,
|
| 793 |
+
entity_id=np.char.mod('%d', chain_key + 1).astype(object),
|
| 794 |
+
entity_desc=np.array(['.'] * len(chain_key), dtype=object),
|
| 795 |
+
)
|
| 796 |
+
|
| 797 |
+
res_key = np.arange(len(res_name), dtype=np.int64)
|
| 798 |
+
res_chain_key = np.repeat(chain_key, chain_res_count)
|
| 799 |
+
residues_table = structure_tables.Residues(
|
| 800 |
+
key=res_key,
|
| 801 |
+
chain_key=res_chain_key,
|
| 802 |
+
id=np.array(res_id, dtype=np.int32),
|
| 803 |
+
name=np.array(res_name, dtype=object),
|
| 804 |
+
auth_seq_id=np.char.mod('%d', res_id).astype(object),
|
| 805 |
+
insertion_code=np.full(len(res_name), '?', dtype=object),
|
| 806 |
+
)
|
| 807 |
+
|
| 808 |
+
num_atoms = current_atom_key
|
| 809 |
+
atom_float32_zeros = np.zeros(num_atoms, dtype=np.float32)
|
| 810 |
+
atoms_table = structure_tables.Atoms(
|
| 811 |
+
key=np.arange(num_atoms, dtype=np.int64),
|
| 812 |
+
chain_key=np.repeat(res_chain_key, res_atom_count),
|
| 813 |
+
res_key=np.repeat(res_key, res_atom_count),
|
| 814 |
+
name=np.array(atom_name, dtype=object),
|
| 815 |
+
element=np.array(atom_element, dtype=object),
|
| 816 |
+
x=atom_float32_zeros,
|
| 817 |
+
y=atom_float32_zeros,
|
| 818 |
+
z=atom_float32_zeros,
|
| 819 |
+
b_factor=atom_float32_zeros,
|
| 820 |
+
occupancy=np.ones(num_atoms, np.float32),
|
| 821 |
+
)
|
| 822 |
+
|
| 823 |
+
return structure.Structure(
|
| 824 |
+
name=name,
|
| 825 |
+
atoms=atoms_table,
|
| 826 |
+
residues=residues_table,
|
| 827 |
+
chains=chains_table,
|
| 828 |
+
bonds=bonds_table,
|
| 829 |
+
chemical_components_data=chem_comp_data,
|
| 830 |
+
**constructor_args,
|
| 831 |
+
)
|
| 832 |
+
|
| 833 |
+
|
| 834 |
+
class _ChainResBuilder:
|
| 835 |
+
"""Class for incrementally building chain and residue tables."""
|
| 836 |
+
|
| 837 |
+
def __init__(
|
| 838 |
+
self,
|
| 839 |
+
*,
|
| 840 |
+
chain_key_by_chain_id: Mapping[str, int],
|
| 841 |
+
entity_id_by_chain_id: Mapping[str, str],
|
| 842 |
+
chain_type_by_entity_id: Mapping[str, str],
|
| 843 |
+
entity_desc_by_entity_id: Mapping[str, str],
|
| 844 |
+
fix_mse_residues: bool,
|
| 845 |
+
fix_unknown_dna: bool,
|
| 846 |
+
):
|
| 847 |
+
# Len: num_chains.
|
| 848 |
+
self.chain_key = []
|
| 849 |
+
self.chain_id = []
|
| 850 |
+
self.chain_type = []
|
| 851 |
+
self.chain_auth_asym_id = []
|
| 852 |
+
self.chain_entity_id = []
|
| 853 |
+
self.chain_entity_desc = []
|
| 854 |
+
|
| 855 |
+
# Len: num_residues.
|
| 856 |
+
self.res_key = []
|
| 857 |
+
self.res_chain_key = []
|
| 858 |
+
self.res_id = []
|
| 859 |
+
self.res_name = []
|
| 860 |
+
self.res_auth_seq_id = []
|
| 861 |
+
self.res_insertion_code = []
|
| 862 |
+
|
| 863 |
+
self.chain_key_by_chain_id = chain_key_by_chain_id
|
| 864 |
+
self.entity_id_by_chain_id = entity_id_by_chain_id
|
| 865 |
+
self.chain_type_by_entity_id = chain_type_by_entity_id
|
| 866 |
+
self.entity_desc_by_entity_id = entity_desc_by_entity_id
|
| 867 |
+
self.key_for_res: dict[tuple[str, str, str, str], int] = {}
|
| 868 |
+
|
| 869 |
+
self._fix_mse_residues = fix_mse_residues
|
| 870 |
+
self._fix_unknown_dna = fix_unknown_dna
|
| 871 |
+
|
| 872 |
+
def add_residues(
|
| 873 |
+
self,
|
| 874 |
+
*,
|
| 875 |
+
chain_ids: np.ndarray,
|
| 876 |
+
chain_auth_asym_ids: np.ndarray,
|
| 877 |
+
res_ids: np.ndarray,
|
| 878 |
+
res_names: np.ndarray,
|
| 879 |
+
res_auth_seq_ids: np.ndarray,
|
| 880 |
+
res_ins_codes: np.ndarray,
|
| 881 |
+
):
|
| 882 |
+
"""Adds a residue (and its chain) to the tables."""
|
| 883 |
+
# Create chain table data.
|
| 884 |
+
if chain_ids.size == 0:
|
| 885 |
+
return
|
| 886 |
+
|
| 887 |
+
chain_ids_with_prev = np.concatenate(
|
| 888 |
+
(([self.chain_id[-1] if self.chain_id else None], chain_ids))
|
| 889 |
+
)
|
| 890 |
+
chain_change_mask = chain_ids_with_prev[:-1] != chain_ids_with_prev[1:]
|
| 891 |
+
chain_change_ids = chain_ids[chain_change_mask]
|
| 892 |
+
chain_keys = string_array.remap(
|
| 893 |
+
chain_change_ids, self.chain_key_by_chain_id, inplace=False
|
| 894 |
+
)
|
| 895 |
+
self.chain_key.extend(chain_keys)
|
| 896 |
+
self.chain_id.extend(chain_change_ids)
|
| 897 |
+
self.chain_auth_asym_id.extend(chain_auth_asym_ids[chain_change_mask])
|
| 898 |
+
chain_entity_id = string_array.remap(
|
| 899 |
+
chain_change_ids, self.entity_id_by_chain_id, inplace=False
|
| 900 |
+
)
|
| 901 |
+
self.chain_entity_id.extend(chain_entity_id)
|
| 902 |
+
chain_type = string_array.remap(
|
| 903 |
+
chain_entity_id, self.chain_type_by_entity_id, inplace=False
|
| 904 |
+
)
|
| 905 |
+
self.chain_type.extend(chain_type)
|
| 906 |
+
chain_entity_desc = string_array.remap(
|
| 907 |
+
chain_entity_id, self.entity_desc_by_entity_id, inplace=False
|
| 908 |
+
)
|
| 909 |
+
self.chain_entity_desc.extend(chain_entity_desc)
|
| 910 |
+
|
| 911 |
+
# Create residue table data.
|
| 912 |
+
num_prev_res = len(self.res_id)
|
| 913 |
+
res_keys = np.arange(num_prev_res, num_prev_res + len(res_ids))
|
| 914 |
+
res_iter = zip(
|
| 915 |
+
chain_ids,
|
| 916 |
+
res_auth_seq_ids,
|
| 917 |
+
res_names,
|
| 918 |
+
res_ins_codes,
|
| 919 |
+
strict=True,
|
| 920 |
+
)
|
| 921 |
+
key_for_res_update = {
|
| 922 |
+
res_unique_id: res_key
|
| 923 |
+
for res_key, res_unique_id in enumerate(res_iter, num_prev_res)
|
| 924 |
+
}
|
| 925 |
+
self.key_for_res.update(key_for_res_update)
|
| 926 |
+
self.res_key.extend(res_keys)
|
| 927 |
+
self.res_chain_key.extend(
|
| 928 |
+
string_array.remap(chain_ids, self.chain_key_by_chain_id, inplace=False)
|
| 929 |
+
)
|
| 930 |
+
self.res_id.extend(res_ids)
|
| 931 |
+
self.res_name.extend(res_names)
|
| 932 |
+
self.res_auth_seq_id.extend(res_auth_seq_ids)
|
| 933 |
+
self.res_insertion_code.extend(res_ins_codes)
|
| 934 |
+
|
| 935 |
+
def make_chains_table(self) -> structure_tables.Chains:
|
| 936 |
+
"""Returns the Structure chains table."""
|
| 937 |
+
chain_key = np.array(self.chain_key, dtype=np.int64)
|
| 938 |
+
if not np.all(chain_key[:-1] <= chain_key[1:]):
|
| 939 |
+
# If the order is inconsistent with the atoms table, sort so that it is.
|
| 940 |
+
order = np.argsort(self.chain_key, kind='stable')
|
| 941 |
+
return structure_tables.Chains(
|
| 942 |
+
key=chain_key[order],
|
| 943 |
+
id=np.array(self.chain_id, dtype=object)[order],
|
| 944 |
+
type=np.array(self.chain_type, dtype=object)[order],
|
| 945 |
+
auth_asym_id=np.array(self.chain_auth_asym_id, dtype=object)[order],
|
| 946 |
+
entity_id=np.array(self.chain_entity_id, dtype=object)[order],
|
| 947 |
+
entity_desc=np.array(self.chain_entity_desc, dtype=object)[order],
|
| 948 |
+
)
|
| 949 |
+
return structure_tables.Chains(
|
| 950 |
+
key=chain_key,
|
| 951 |
+
id=np.array(self.chain_id, dtype=object),
|
| 952 |
+
type=np.array(self.chain_type, dtype=object),
|
| 953 |
+
auth_asym_id=np.array(self.chain_auth_asym_id, dtype=object),
|
| 954 |
+
entity_id=np.array(self.chain_entity_id, dtype=object),
|
| 955 |
+
entity_desc=np.array(self.chain_entity_desc, dtype=object),
|
| 956 |
+
)
|
| 957 |
+
|
| 958 |
+
def make_residues_table(self) -> structure_tables.Residues:
|
| 959 |
+
"""Returns the Structure residues table."""
|
| 960 |
+
res_name = np.array(self.res_name, dtype=object)
|
| 961 |
+
res_chain_key = np.array(self.res_chain_key, dtype=np.int64)
|
| 962 |
+
|
| 963 |
+
if self._fix_mse_residues:
|
| 964 |
+
string_array.remap(res_name, mapping={'MSE': 'MET'}, inplace=True)
|
| 965 |
+
|
| 966 |
+
if self._fix_unknown_dna:
|
| 967 |
+
# Remap residues from N -> DN in DNA chains only.
|
| 968 |
+
dna_chain_mask = (
|
| 969 |
+
np.array(self.chain_type, dtype=object) == mmcif_names.DNA_CHAIN
|
| 970 |
+
)
|
| 971 |
+
dna_chain_key = np.array(self.chain_key, dtype=object)[dna_chain_mask]
|
| 972 |
+
res_name[(res_name == 'N') & np.isin(res_chain_key, dna_chain_key)] = 'DN'
|
| 973 |
+
|
| 974 |
+
if not np.all(res_chain_key[:-1] <= res_chain_key[1:]):
|
| 975 |
+
# If the order is inconsistent with the atoms table, sort so that it is.
|
| 976 |
+
order = np.argsort(res_chain_key, kind='stable')
|
| 977 |
+
return structure_tables.Residues(
|
| 978 |
+
key=np.array(self.res_key, dtype=np.int64)[order],
|
| 979 |
+
chain_key=res_chain_key[order],
|
| 980 |
+
id=np.array(self.res_id, dtype=np.int32)[order],
|
| 981 |
+
name=res_name[order],
|
| 982 |
+
auth_seq_id=np.array(self.res_auth_seq_id, dtype=object)[order],
|
| 983 |
+
insertion_code=np.array(self.res_insertion_code, dtype=object)[order],
|
| 984 |
+
)
|
| 985 |
+
return structure_tables.Residues(
|
| 986 |
+
key=np.array(self.res_key, dtype=np.int64),
|
| 987 |
+
chain_key=res_chain_key,
|
| 988 |
+
id=np.array(self.res_id, dtype=np.int32),
|
| 989 |
+
name=res_name,
|
| 990 |
+
auth_seq_id=np.array(self.res_auth_seq_id, dtype=object),
|
| 991 |
+
insertion_code=np.array(self.res_insertion_code, dtype=object),
|
| 992 |
+
)
|
| 993 |
+
|
| 994 |
+
|
| 995 |
+
def _get_string_array_default(cif: mmcif.Mmcif, key: str, default: list[str]):
|
| 996 |
+
try:
|
| 997 |
+
return cif.get_array(key, dtype=object)
|
| 998 |
+
except KeyError:
|
| 999 |
+
return default
|
| 1000 |
+
|
| 1001 |
+
|
| 1002 |
+
def _generate_required_tables_if_missing(
|
| 1003 |
+
cif: mmcif.Mmcif,
|
| 1004 |
+
) -> Mapping[str, Sequence[str]]:
|
| 1005 |
+
"""Generates all required tables and columns if missing."""
|
| 1006 |
+
update = {}
|
| 1007 |
+
|
| 1008 |
+
atom_site_entities = _get_string_array_default(
|
| 1009 |
+
cif, '_atom_site.label_entity_id', []
|
| 1010 |
+
)
|
| 1011 |
+
|
| 1012 |
+
# OpenMM produces files that don't have any of the tables and also have
|
| 1013 |
+
# _atom_site.label_entity_id set to '?' for all atoms. We infer the entities
|
| 1014 |
+
# based on the _atom_site.label_asym_id column. We start with cheaper O(1)
|
| 1015 |
+
# checks to prevent running the expensive O(n) check on most files.
|
| 1016 |
+
if (
|
| 1017 |
+
len(atom_site_entities) > 0 # pylint: disable=g-explicit-length-test
|
| 1018 |
+
and '_entity.id' not in cif # Ignore if the _entity table exists.
|
| 1019 |
+
and atom_site_entities[0] == '?' # Cheap check.
|
| 1020 |
+
and set(atom_site_entities) == {'?'} # Expensive check.
|
| 1021 |
+
):
|
| 1022 |
+
label_asym_ids = cif.get_array('_atom_site.label_asym_id', dtype=object)
|
| 1023 |
+
atom_site_entities = [
|
| 1024 |
+
str(mmcif.str_id_to_int_id(cid)) for cid in label_asym_ids
|
| 1025 |
+
]
|
| 1026 |
+
# Update _atom_site.label_entity_id to be consistent with the new tables.
|
| 1027 |
+
update['_atom_site.label_entity_id'] = atom_site_entities
|
| 1028 |
+
|
| 1029 |
+
# Check table existence by checking the presence of its primary key.
|
| 1030 |
+
if '_struct_asym.id' not in cif:
|
| 1031 |
+
# Infer the _struct_asym table using the _atom_site table.
|
| 1032 |
+
asym_ids = _get_string_array_default(cif, '_atom_site.label_asym_id', [])
|
| 1033 |
+
|
| 1034 |
+
if len(atom_site_entities) == 0 or len(asym_ids) == 0: # pylint: disable=g-explicit-length-test
|
| 1035 |
+
raise ValueError(
|
| 1036 |
+
'Could not parse an mmCIF with no _struct_asym table and also no '
|
| 1037 |
+
'_atom_site.label_entity_id or _atom_site.label_asym_id columns.'
|
| 1038 |
+
)
|
| 1039 |
+
|
| 1040 |
+
# Deduplicate, but keep the order intact - dict.fromkeys maintains order.
|
| 1041 |
+
entity_id_chain_id_pairs = list(
|
| 1042 |
+
dict.fromkeys(zip(atom_site_entities, asym_ids, strict=True))
|
| 1043 |
+
)
|
| 1044 |
+
update['_struct_asym.entity_id'] = [e for e, _ in entity_id_chain_id_pairs]
|
| 1045 |
+
update['_struct_asym.id'] = [c for _, c in entity_id_chain_id_pairs]
|
| 1046 |
+
|
| 1047 |
+
if '_entity.id' not in cif:
|
| 1048 |
+
# Infer the _entity_poly and _entity tables using the _atom_site table.
|
| 1049 |
+
residues = _get_string_array_default(cif, '_atom_site.label_comp_id', [])
|
| 1050 |
+
group_pdb = _get_string_array_default(cif, '_atom_site.group_PDB', [])
|
| 1051 |
+
if '_atom_site.label_entity_id' in cif:
|
| 1052 |
+
entities = atom_site_entities
|
| 1053 |
+
else:
|
| 1054 |
+
# If _atom_site.label_entity_id not set, use the asym_id -> entity_id map.
|
| 1055 |
+
asym_to_entity = dict(
|
| 1056 |
+
zip(
|
| 1057 |
+
cif['_struct_asym.id'], cif['_struct_asym.entity_id'], strict=True
|
| 1058 |
+
)
|
| 1059 |
+
)
|
| 1060 |
+
entities = string_array.remap(
|
| 1061 |
+
cif.get_array('_atom_site.label_asym_id', dtype=object),
|
| 1062 |
+
mapping=asym_to_entity,
|
| 1063 |
+
)
|
| 1064 |
+
|
| 1065 |
+
entity_ids = []
|
| 1066 |
+
entity_types = []
|
| 1067 |
+
entity_poly_entity_ids = []
|
| 1068 |
+
entity_poly_types = []
|
| 1069 |
+
entity_poly_table_missing = '_entity_poly.entity_id' not in cif
|
| 1070 |
+
for entity_id, group in itertools.groupby(
|
| 1071 |
+
zip(entities, residues, group_pdb, strict=True), key=lambda e: e[0]
|
| 1072 |
+
):
|
| 1073 |
+
_, entity_residues, entity_group_pdb = zip(*group, strict=True)
|
| 1074 |
+
entity_type = _guess_entity_type(
|
| 1075 |
+
chain_residues=entity_residues, atom_types=entity_group_pdb
|
| 1076 |
+
)
|
| 1077 |
+
entity_ids.append(entity_id)
|
| 1078 |
+
entity_types.append(entity_type)
|
| 1079 |
+
|
| 1080 |
+
if entity_poly_table_missing and entity_type == mmcif_names.POLYMER_CHAIN:
|
| 1081 |
+
polymer_type = mmcif_names.guess_polymer_type(entity_residues)
|
| 1082 |
+
entity_poly_entity_ids.append(entity_id)
|
| 1083 |
+
entity_poly_types.append(polymer_type)
|
| 1084 |
+
|
| 1085 |
+
update['_entity.id'] = entity_ids
|
| 1086 |
+
update['_entity.type'] = entity_types
|
| 1087 |
+
if entity_poly_table_missing:
|
| 1088 |
+
update['_entity_poly.entity_id'] = entity_poly_entity_ids
|
| 1089 |
+
update['_entity_poly.type'] = entity_poly_types
|
| 1090 |
+
|
| 1091 |
+
if '_atom_site.type_symbol' not in cif:
|
| 1092 |
+
update['_atom_site.type_symbol'] = mmcif.get_or_infer_type_symbol(cif)
|
| 1093 |
+
|
| 1094 |
+
return update
|
| 1095 |
+
|
| 1096 |
+
|
| 1097 |
+
def _maybe_add_missing_scheme_tables(
|
| 1098 |
+
cif: mmcif.Mmcif,
|
| 1099 |
+
res_starts: Sequence[int],
|
| 1100 |
+
label_asym_ids: np.ndarray,
|
| 1101 |
+
label_seq_ids: np.ndarray,
|
| 1102 |
+
label_comp_ids: np.ndarray,
|
| 1103 |
+
auth_seq_ids: np.ndarray,
|
| 1104 |
+
pdb_ins_codes: np.ndarray,
|
| 1105 |
+
) -> Mapping[str, Sequence[str]]:
|
| 1106 |
+
"""If missing, infers the scheme tables from the _atom_site table."""
|
| 1107 |
+
update = {}
|
| 1108 |
+
|
| 1109 |
+
required_poly_seq_scheme_cols = (
|
| 1110 |
+
'_pdbx_poly_seq_scheme.asym_id',
|
| 1111 |
+
'_pdbx_poly_seq_scheme.pdb_seq_num',
|
| 1112 |
+
'_pdbx_poly_seq_scheme.pdb_ins_code',
|
| 1113 |
+
'_pdbx_poly_seq_scheme.seq_id',
|
| 1114 |
+
'_pdbx_poly_seq_scheme.mon_id',
|
| 1115 |
+
'_pdbx_poly_seq_scheme.pdb_strand_id',
|
| 1116 |
+
)
|
| 1117 |
+
if not all(col in cif for col in required_poly_seq_scheme_cols):
|
| 1118 |
+
# Create a mask for atoms where each polymer residue start.
|
| 1119 |
+
entity_id_by_chain_id = dict(
|
| 1120 |
+
zip(cif['_struct_asym.id'], cif['_struct_asym.entity_id'], strict=True)
|
| 1121 |
+
)
|
| 1122 |
+
chain_type_by_entity_id = dict(
|
| 1123 |
+
zip(cif['_entity.id'], cif['_entity.type'], strict=True)
|
| 1124 |
+
)
|
| 1125 |
+
# Remap asym ID -> entity ID.
|
| 1126 |
+
label_entity_id = string_array.remap(
|
| 1127 |
+
label_asym_ids, mapping=entity_id_by_chain_id, inplace=False
|
| 1128 |
+
)
|
| 1129 |
+
# Remap entity ID -> chain type.
|
| 1130 |
+
chain_type = string_array.remap(
|
| 1131 |
+
label_entity_id, mapping=chain_type_by_entity_id, inplace=False
|
| 1132 |
+
)
|
| 1133 |
+
res_mask = np.zeros_like(label_seq_ids, dtype=bool)
|
| 1134 |
+
res_mask[res_starts] = True
|
| 1135 |
+
res_mask &= chain_type == mmcif_names.POLYMER_CHAIN
|
| 1136 |
+
|
| 1137 |
+
entity_poly_seq_cols = (
|
| 1138 |
+
'_entity_poly_seq.entity_id',
|
| 1139 |
+
'_entity_poly_seq.num',
|
| 1140 |
+
'_entity_poly_seq.mon_id',
|
| 1141 |
+
)
|
| 1142 |
+
if all(col in cif for col in entity_poly_seq_cols):
|
| 1143 |
+
# Use _entity_poly_seq if available.
|
| 1144 |
+
poly_seq_num = cif.get_array('_entity_poly_seq.num', dtype=object)
|
| 1145 |
+
poly_seq_mon_id = cif.get_array('_entity_poly_seq.mon_id', dtype=object)
|
| 1146 |
+
poly_seq_entity_id = cif.get_array(
|
| 1147 |
+
'_entity_poly_seq.entity_id', dtype=object
|
| 1148 |
+
)
|
| 1149 |
+
# We have to add the entity ID to the residue ID because multiple residues
|
| 1150 |
+
# can share the same ID. This also allows using string_array.remap.
|
| 1151 |
+
label_seq_id_to_auth_seq_id = dict(
|
| 1152 |
+
zip(
|
| 1153 |
+
np.char.add(label_entity_id[res_mask], label_seq_ids[res_mask]),
|
| 1154 |
+
auth_seq_ids[res_mask],
|
| 1155 |
+
strict=True,
|
| 1156 |
+
)
|
| 1157 |
+
)
|
| 1158 |
+
scheme_pdb_seq_num = string_array.remap(
|
| 1159 |
+
np.char.add(poly_seq_entity_id, poly_seq_num),
|
| 1160 |
+
mapping=label_seq_id_to_auth_seq_id,
|
| 1161 |
+
default_value='.',
|
| 1162 |
+
)
|
| 1163 |
+
label_seq_id_to_ins_code = dict(
|
| 1164 |
+
zip(label_seq_ids[res_mask], pdb_ins_codes[res_mask], strict=True)
|
| 1165 |
+
)
|
| 1166 |
+
scheme_pdb_ins_code = string_array.remap(
|
| 1167 |
+
poly_seq_num, mapping=label_seq_id_to_ins_code, default_value='.'
|
| 1168 |
+
)
|
| 1169 |
+
|
| 1170 |
+
# The _entity_poly_seq table is entity-based, while _pdbx_poly_seq_scheme
|
| 1171 |
+
# is chain-based. A single entity could mean multiple chains (asym_ids),
|
| 1172 |
+
# we therefore need to replicate each entity for all of the chains.
|
| 1173 |
+
scheme_asym_id = []
|
| 1174 |
+
select = []
|
| 1175 |
+
indices = np.arange(len(poly_seq_entity_id), dtype=np.int32)
|
| 1176 |
+
for asym_id, entity_id in zip(
|
| 1177 |
+
cif['_struct_asym.id'], cif['_struct_asym.entity_id'], strict=True
|
| 1178 |
+
):
|
| 1179 |
+
entity_mask = poly_seq_entity_id == entity_id
|
| 1180 |
+
select.extend(indices[entity_mask])
|
| 1181 |
+
scheme_asym_id.extend([asym_id] * sum(entity_mask))
|
| 1182 |
+
|
| 1183 |
+
scheme_pdb_strand_id = string_array.remap(
|
| 1184 |
+
np.array(scheme_asym_id, dtype=object),
|
| 1185 |
+
mapping=mmcif.get_internal_to_author_chain_id_map(cif),
|
| 1186 |
+
inplace=False,
|
| 1187 |
+
)
|
| 1188 |
+
|
| 1189 |
+
update['_pdbx_poly_seq_scheme.asym_id'] = scheme_asym_id
|
| 1190 |
+
update['_pdbx_poly_seq_scheme.pdb_strand_id'] = scheme_pdb_strand_id
|
| 1191 |
+
update['_pdbx_poly_seq_scheme.pdb_seq_num'] = scheme_pdb_seq_num[select]
|
| 1192 |
+
update['_pdbx_poly_seq_scheme.pdb_ins_code'] = scheme_pdb_ins_code[select]
|
| 1193 |
+
update['_pdbx_poly_seq_scheme.seq_id'] = poly_seq_num[select]
|
| 1194 |
+
update['_pdbx_poly_seq_scheme.mon_id'] = poly_seq_mon_id[select]
|
| 1195 |
+
else:
|
| 1196 |
+
# _entity_poly_seq not available, fallback to _atom_site.
|
| 1197 |
+
res_asym_ids = label_asym_ids[res_mask]
|
| 1198 |
+
res_strand_ids = string_array.remap(
|
| 1199 |
+
array=res_asym_ids,
|
| 1200 |
+
mapping=mmcif.get_internal_to_author_chain_id_map(cif),
|
| 1201 |
+
inplace=False,
|
| 1202 |
+
)
|
| 1203 |
+
update['_pdbx_poly_seq_scheme.asym_id'] = res_asym_ids
|
| 1204 |
+
update['_pdbx_poly_seq_scheme.pdb_strand_id'] = res_strand_ids
|
| 1205 |
+
update['_pdbx_poly_seq_scheme.pdb_seq_num'] = auth_seq_ids[res_mask]
|
| 1206 |
+
update['_pdbx_poly_seq_scheme.pdb_ins_code'] = pdb_ins_codes[res_mask]
|
| 1207 |
+
update['_pdbx_poly_seq_scheme.seq_id'] = label_seq_ids[res_mask]
|
| 1208 |
+
update['_pdbx_poly_seq_scheme.mon_id'] = label_comp_ids[res_mask]
|
| 1209 |
+
|
| 1210 |
+
required_nonpoly_scheme_cols = (
|
| 1211 |
+
'_pdbx_nonpoly_scheme.mon_id',
|
| 1212 |
+
'_pdbx_nonpoly_scheme.asym_id',
|
| 1213 |
+
'_pdbx_nonpoly_scheme.pdb_seq_num',
|
| 1214 |
+
'_pdbx_nonpoly_scheme.pdb_ins_code',
|
| 1215 |
+
)
|
| 1216 |
+
required_branch_scheme_cols = (
|
| 1217 |
+
'_pdbx_branch_scheme.mon_id',
|
| 1218 |
+
'_pdbx_branch_scheme.asym_id',
|
| 1219 |
+
'_pdbx_branch_scheme.pdb_seq_num',
|
| 1220 |
+
)
|
| 1221 |
+
|
| 1222 |
+
# Generate _pdbx_nonpoly_scheme only if both tables are missing.
|
| 1223 |
+
if not (
|
| 1224 |
+
all(col in cif for col in required_nonpoly_scheme_cols)
|
| 1225 |
+
or all(col in cif for col in required_branch_scheme_cols)
|
| 1226 |
+
):
|
| 1227 |
+
# To be strictly semantically correct, multi-residue ligands should be
|
| 1228 |
+
# written in _pdbx_branch_scheme. However, Structure parsing handles
|
| 1229 |
+
# correctly multi-residue ligands in _pdbx_nonpoly_scheme and the tables
|
| 1230 |
+
# constructed here live only while parsing, hence this is unnecessary.
|
| 1231 |
+
entity_id_by_chain_id = dict(
|
| 1232 |
+
zip(cif['_struct_asym.id'], cif['_struct_asym.entity_id'], strict=True)
|
| 1233 |
+
)
|
| 1234 |
+
chain_type_by_entity_id = dict(
|
| 1235 |
+
zip(cif['_entity.id'], cif['_entity.type'], strict=True)
|
| 1236 |
+
)
|
| 1237 |
+
# Remap asym ID -> entity ID.
|
| 1238 |
+
chain_type = string_array.remap(
|
| 1239 |
+
label_asym_ids, mapping=entity_id_by_chain_id, inplace=False
|
| 1240 |
+
)
|
| 1241 |
+
# Remap entity ID -> chain type.
|
| 1242 |
+
string_array.remap(
|
| 1243 |
+
chain_type, mapping=chain_type_by_entity_id, inplace=True
|
| 1244 |
+
)
|
| 1245 |
+
res_mask = np.zeros_like(label_seq_ids, dtype=bool)
|
| 1246 |
+
res_mask[res_starts] = True
|
| 1247 |
+
res_mask &= chain_type != mmcif_names.POLYMER_CHAIN
|
| 1248 |
+
|
| 1249 |
+
if not np.any(res_mask):
|
| 1250 |
+
return update # Shortcut: no non-polymer residues.
|
| 1251 |
+
|
| 1252 |
+
ins_codes = string_array.remap(
|
| 1253 |
+
pdb_ins_codes[res_mask], mapping={'?': '.'}, inplace=False
|
| 1254 |
+
)
|
| 1255 |
+
|
| 1256 |
+
update['_pdbx_nonpoly_scheme.asym_id'] = label_asym_ids[res_mask]
|
| 1257 |
+
update['_pdbx_nonpoly_scheme.pdb_seq_num'] = auth_seq_ids[res_mask]
|
| 1258 |
+
update['_pdbx_nonpoly_scheme.pdb_ins_code'] = ins_codes
|
| 1259 |
+
update['_pdbx_nonpoly_scheme.mon_id'] = label_comp_ids[res_mask]
|
| 1260 |
+
|
| 1261 |
+
return update
|
| 1262 |
+
|
| 1263 |
+
|
| 1264 |
+
def _get_chain_key_by_chain_id(
|
| 1265 |
+
resolved_chain_ids: np.ndarray, struct_asym_chain_ids: np.ndarray
|
| 1266 |
+
) -> Mapping[str, int]:
|
| 1267 |
+
"""Returns chain key for each chain ID respecting resolved chain ordering."""
|
| 1268 |
+
# Check that all chain IDs found in the (potentially filtered) _atom_site
|
| 1269 |
+
# table are present in the _struct_asym table.
|
| 1270 |
+
unique_resolved_chain_ids = set(resolved_chain_ids)
|
| 1271 |
+
if not unique_resolved_chain_ids.issubset(set(struct_asym_chain_ids)):
|
| 1272 |
+
unique_resolved_chain_ids = sorted(unique_resolved_chain_ids)
|
| 1273 |
+
unique_struct_asym_chain_ids = sorted(set(struct_asym_chain_ids))
|
| 1274 |
+
raise ValueError(
|
| 1275 |
+
'Bad mmCIF: chain IDs in _atom_site.label_asym_id '
|
| 1276 |
+
f'{unique_resolved_chain_ids} is not a subset of chain IDs in '
|
| 1277 |
+
f'_struct_asym.id {unique_struct_asym_chain_ids}.'
|
| 1278 |
+
)
|
| 1279 |
+
|
| 1280 |
+
resolved_mask = string_array.isin(
|
| 1281 |
+
struct_asym_chain_ids, unique_resolved_chain_ids
|
| 1282 |
+
)
|
| 1283 |
+
# For all resolved chains, use the _atom_site order they appear in. E.g.
|
| 1284 |
+
# resolved_chain_ids = [B A E D F]
|
| 1285 |
+
# struct_asym_chain_ids = [A B C D E F]
|
| 1286 |
+
# consistent_chain_order = [B A C E D F]
|
| 1287 |
+
# chain_keys = [0 1 2 3 4 5]
|
| 1288 |
+
consistent_chain_order = struct_asym_chain_ids.copy()
|
| 1289 |
+
consistent_chain_order[resolved_mask] = resolved_chain_ids
|
| 1290 |
+
return dict(zip(consistent_chain_order, range(len(struct_asym_chain_ids))))
|
| 1291 |
+
|
| 1292 |
+
|
| 1293 |
+
def get_tables(
|
| 1294 |
+
cif: mmcif.Mmcif,
|
| 1295 |
+
fix_mse_residues: bool,
|
| 1296 |
+
fix_arginines: bool,
|
| 1297 |
+
fix_unknown_dna: bool,
|
| 1298 |
+
include_water: bool,
|
| 1299 |
+
include_other: bool,
|
| 1300 |
+
model_id: str,
|
| 1301 |
+
) -> tuple[
|
| 1302 |
+
structure_tables.Chains, structure_tables.Residues, structure_tables.Atoms
|
| 1303 |
+
]:
|
| 1304 |
+
"""Returns chain, residue, and atom tables from a parsed mmcif.
|
| 1305 |
+
|
| 1306 |
+
Args:
|
| 1307 |
+
cif: A parsed mmcif.Mmcif.
|
| 1308 |
+
fix_mse_residues: See from_mmcif.
|
| 1309 |
+
fix_arginines: See from_mmcif.
|
| 1310 |
+
fix_unknown_dna: See from_mmcif.
|
| 1311 |
+
include_water: See from_mmcif.
|
| 1312 |
+
include_other: See from_mmcif.
|
| 1313 |
+
model_id: A string defining which model ID to use. If set, only coordinates,
|
| 1314 |
+
b-factors and occupancies for the given model are returned. If empty,
|
| 1315 |
+
coordinates, b-factors and occupanciesall for models are returned with a
|
| 1316 |
+
leading dimension of num_models. Note that the model_id argument in
|
| 1317 |
+
from_mmcif is an integer and has slightly different use (see from_mmcif).
|
| 1318 |
+
"""
|
| 1319 |
+
# Add any missing tables and columns we require for parsing.
|
| 1320 |
+
if cif_update := _generate_required_tables_if_missing(cif):
|
| 1321 |
+
cif = cif.copy_and_update(cif_update)
|
| 1322 |
+
|
| 1323 |
+
# Resolve alt-locs, selecting only a single option for each residue. Also
|
| 1324 |
+
# computes the layout, which defines where chain and residue boundaries are.
|
| 1325 |
+
atom_site_all_models, layout = mmcif_utils.filter(
|
| 1326 |
+
cif,
|
| 1327 |
+
include_nucleotides=True,
|
| 1328 |
+
include_ligands=True,
|
| 1329 |
+
include_water=include_water,
|
| 1330 |
+
include_other=include_other,
|
| 1331 |
+
model_id=model_id,
|
| 1332 |
+
)
|
| 1333 |
+
atom_site_first_model = atom_site_all_models[0]
|
| 1334 |
+
|
| 1335 |
+
# Get atom information from the _atom_site table.
|
| 1336 |
+
def _first_model_string_array(col: str) -> np.ndarray:
|
| 1337 |
+
return cif.get_array(col, dtype=object, gather=atom_site_first_model)
|
| 1338 |
+
|
| 1339 |
+
def _requested_models_float_array(col: str) -> np.ndarray:
|
| 1340 |
+
if not model_id:
|
| 1341 |
+
# Return data for all models with a leading dimension of num_models.
|
| 1342 |
+
return cif.get_array(col, dtype=np.float32, gather=atom_site_all_models)
|
| 1343 |
+
else:
|
| 1344 |
+
# Return data only for the single requested model.
|
| 1345 |
+
return cif.get_array(col, dtype=np.float32, gather=atom_site_first_model)
|
| 1346 |
+
|
| 1347 |
+
# These columns are the same for all models, fetch them just for the 1st one.
|
| 1348 |
+
label_comp_ids = _first_model_string_array('_atom_site.label_comp_id')
|
| 1349 |
+
label_asym_ids = _first_model_string_array('_atom_site.label_asym_id')
|
| 1350 |
+
label_seq_ids = _first_model_string_array('_atom_site.label_seq_id')
|
| 1351 |
+
label_atom_ids = _first_model_string_array('_atom_site.label_atom_id')
|
| 1352 |
+
if '_atom_site.auth_seq_id' in cif:
|
| 1353 |
+
auth_seq_ids = _first_model_string_array('_atom_site.auth_seq_id')
|
| 1354 |
+
else:
|
| 1355 |
+
auth_seq_ids = label_seq_ids # auth_seq_id unset, fallback to label_seq_id.
|
| 1356 |
+
type_symbols = _first_model_string_array('_atom_site.type_symbol')
|
| 1357 |
+
pdbx_pdb_ins_codes = _first_model_string_array('_atom_site.pdbx_PDB_ins_code')
|
| 1358 |
+
|
| 1359 |
+
# These columns are different for all models, fetch them as requested.
|
| 1360 |
+
atom_x = _requested_models_float_array('_atom_site.Cartn_x')
|
| 1361 |
+
atom_y = _requested_models_float_array('_atom_site.Cartn_y')
|
| 1362 |
+
atom_z = _requested_models_float_array('_atom_site.Cartn_z')
|
| 1363 |
+
atom_b_factor = _requested_models_float_array('_atom_site.B_iso_or_equiv')
|
| 1364 |
+
atom_occupancy = _requested_models_float_array('_atom_site.occupancy')
|
| 1365 |
+
|
| 1366 |
+
# Make sure the scheme (residue) tables exist in case they are not present.
|
| 1367 |
+
if cif_update := _maybe_add_missing_scheme_tables(
|
| 1368 |
+
cif,
|
| 1369 |
+
res_starts=layout.residue_starts(),
|
| 1370 |
+
label_asym_ids=label_asym_ids,
|
| 1371 |
+
label_seq_ids=label_seq_ids,
|
| 1372 |
+
label_comp_ids=label_comp_ids,
|
| 1373 |
+
auth_seq_ids=auth_seq_ids,
|
| 1374 |
+
pdb_ins_codes=pdbx_pdb_ins_codes,
|
| 1375 |
+
):
|
| 1376 |
+
cif = cif.copy_and_update(cif_update)
|
| 1377 |
+
|
| 1378 |
+
# Fix common issues found in mmCIF files, like swapped arginine NH atoms.
|
| 1379 |
+
mmcif_utils.fix_residues(
|
| 1380 |
+
layout,
|
| 1381 |
+
comp_id=label_comp_ids,
|
| 1382 |
+
atom_id=label_atom_ids,
|
| 1383 |
+
atom_x=atom_x[0] if not model_id else atom_x,
|
| 1384 |
+
atom_y=atom_y[0] if not model_id else atom_y,
|
| 1385 |
+
atom_z=atom_z[0] if not model_id else atom_z,
|
| 1386 |
+
fix_arg=fix_arginines,
|
| 1387 |
+
)
|
| 1388 |
+
|
| 1389 |
+
# Get keys for chains in the order they appear in _atom_site while also
|
| 1390 |
+
# dealing with empty chains.
|
| 1391 |
+
resolved_chain_ids = label_asym_ids[layout.chain_starts()]
|
| 1392 |
+
struct_asym_chain_ids = cif.get_array('_struct_asym.id', dtype=object)
|
| 1393 |
+
|
| 1394 |
+
chain_key_by_chain_id = _get_chain_key_by_chain_id(
|
| 1395 |
+
resolved_chain_ids=resolved_chain_ids,
|
| 1396 |
+
struct_asym_chain_ids=struct_asym_chain_ids,
|
| 1397 |
+
)
|
| 1398 |
+
entity_id_by_chain_id = dict(
|
| 1399 |
+
zip(struct_asym_chain_ids, cif['_struct_asym.entity_id'], strict=True)
|
| 1400 |
+
)
|
| 1401 |
+
entity_description = cif.get(
|
| 1402 |
+
'_entity.pdbx_description', ['?'] * len(cif['_entity.id'])
|
| 1403 |
+
)
|
| 1404 |
+
entity_desc_by_entity_id = dict(
|
| 1405 |
+
zip(cif['_entity.id'], entity_description, strict=True)
|
| 1406 |
+
)
|
| 1407 |
+
chain_type_by_entity_id = mmcif.get_chain_type_by_entity_id(cif)
|
| 1408 |
+
auth_asym_id_by_chain_id = mmcif.get_internal_to_author_chain_id_map(cif)
|
| 1409 |
+
|
| 1410 |
+
chain_res_builder = _ChainResBuilder(
|
| 1411 |
+
chain_key_by_chain_id=chain_key_by_chain_id,
|
| 1412 |
+
entity_id_by_chain_id=entity_id_by_chain_id,
|
| 1413 |
+
chain_type_by_entity_id=chain_type_by_entity_id,
|
| 1414 |
+
entity_desc_by_entity_id=entity_desc_by_entity_id,
|
| 1415 |
+
fix_mse_residues=fix_mse_residues,
|
| 1416 |
+
fix_unknown_dna=fix_unknown_dna,
|
| 1417 |
+
)
|
| 1418 |
+
|
| 1419 |
+
# Collect data for polymer chain and residue tables. _pdbx_poly_seq_scheme is
|
| 1420 |
+
# guaranteed to be present thanks to _maybe_add_missing_scheme_tables.
|
| 1421 |
+
def _get_poly_seq_scheme_col(col: str) -> np.ndarray:
|
| 1422 |
+
return cif.get_array(key=f'_pdbx_poly_seq_scheme.{col}', dtype=object)
|
| 1423 |
+
|
| 1424 |
+
poly_seq_asym_ids = _get_poly_seq_scheme_col('asym_id')
|
| 1425 |
+
poly_seq_pdb_seq_nums = _get_poly_seq_scheme_col('pdb_seq_num')
|
| 1426 |
+
poly_seq_seq_ids = _get_poly_seq_scheme_col('seq_id')
|
| 1427 |
+
poly_seq_mon_ids = _get_poly_seq_scheme_col('mon_id')
|
| 1428 |
+
poly_seq_pdb_strand_ids = _get_poly_seq_scheme_col('pdb_strand_id')
|
| 1429 |
+
poly_seq_pdb_ins_codes = _get_poly_seq_scheme_col('pdb_ins_code')
|
| 1430 |
+
string_array.remap(
|
| 1431 |
+
poly_seq_pdb_ins_codes, mapping=_INSERTION_CODE_REMAP, inplace=True
|
| 1432 |
+
)
|
| 1433 |
+
|
| 1434 |
+
# We resolved alt-locs earlier for the atoms table. In cases of heterogeneous
|
| 1435 |
+
# residues (a residue with an alt-loc that is of different residue type), we
|
| 1436 |
+
# need to also do the same resolution in the residues table. Compute a mask
|
| 1437 |
+
# for the residues that were selected in the atoms table.
|
| 1438 |
+
poly_seq_mask = mmcif_utils.selected_polymer_residue_mask(
|
| 1439 |
+
layout=layout,
|
| 1440 |
+
atom_site_label_asym_ids=label_asym_ids[layout.residue_starts()],
|
| 1441 |
+
atom_site_label_seq_ids=label_seq_ids[layout.residue_starts()],
|
| 1442 |
+
atom_site_label_comp_ids=label_comp_ids[layout.residue_starts()],
|
| 1443 |
+
poly_seq_asym_ids=poly_seq_asym_ids,
|
| 1444 |
+
poly_seq_seq_ids=poly_seq_seq_ids,
|
| 1445 |
+
poly_seq_mon_ids=poly_seq_mon_ids,
|
| 1446 |
+
)
|
| 1447 |
+
|
| 1448 |
+
if not include_other and poly_seq_mask:
|
| 1449 |
+
# Mask filtered-out residues so that they are not treated as missing.
|
| 1450 |
+
# Instead, we don't want them included in the chains/residues tables at all.
|
| 1451 |
+
keep_mask = string_array.remap(
|
| 1452 |
+
poly_seq_asym_ids,
|
| 1453 |
+
mapping={cid: True for cid in resolved_chain_ids},
|
| 1454 |
+
default_value=False,
|
| 1455 |
+
inplace=False,
|
| 1456 |
+
).astype(bool)
|
| 1457 |
+
poly_seq_mask &= keep_mask
|
| 1458 |
+
|
| 1459 |
+
chain_res_builder.add_residues(
|
| 1460 |
+
chain_ids=poly_seq_asym_ids[poly_seq_mask],
|
| 1461 |
+
chain_auth_asym_ids=poly_seq_pdb_strand_ids[poly_seq_mask],
|
| 1462 |
+
res_ids=poly_seq_seq_ids[poly_seq_mask].astype(np.int32),
|
| 1463 |
+
res_names=poly_seq_mon_ids[poly_seq_mask],
|
| 1464 |
+
res_auth_seq_ids=poly_seq_pdb_seq_nums[poly_seq_mask],
|
| 1465 |
+
res_ins_codes=poly_seq_pdb_ins_codes[poly_seq_mask],
|
| 1466 |
+
)
|
| 1467 |
+
|
| 1468 |
+
# Collect data for ligand chain and residue tables. _pdbx_nonpoly_scheme
|
| 1469 |
+
# could be empty/unset if there are only branched ligands.
|
| 1470 |
+
def _get_nonpoly_scheme_col(col: str) -> np.ndarray:
|
| 1471 |
+
key = f'_pdbx_nonpoly_scheme.{col}'
|
| 1472 |
+
if f'_pdbx_nonpoly_scheme.{col}' in cif:
|
| 1473 |
+
return cif.get_array(key=key, dtype=object)
|
| 1474 |
+
else:
|
| 1475 |
+
return np.array([], dtype=object)
|
| 1476 |
+
|
| 1477 |
+
nonpoly_asym_ids = _get_nonpoly_scheme_col('asym_id')
|
| 1478 |
+
nonpoly_auth_seq_ids = _get_nonpoly_scheme_col('pdb_seq_num')
|
| 1479 |
+
nonpoly_pdb_ins_codes = _get_nonpoly_scheme_col('pdb_ins_code')
|
| 1480 |
+
nonpoly_mon_ids = _get_nonpoly_scheme_col('mon_id')
|
| 1481 |
+
nonpoly_auth_asym_id = string_array.remap(
|
| 1482 |
+
nonpoly_asym_ids, mapping=auth_asym_id_by_chain_id, inplace=False
|
| 1483 |
+
)
|
| 1484 |
+
|
| 1485 |
+
def _get_branch_scheme_col(col: str) -> np.ndarray:
|
| 1486 |
+
key = f'_pdbx_branch_scheme.{col}'
|
| 1487 |
+
if f'_pdbx_branch_scheme.{col}' in cif:
|
| 1488 |
+
return cif.get_array(key=key, dtype=object)
|
| 1489 |
+
else:
|
| 1490 |
+
return np.array([], dtype=object)
|
| 1491 |
+
|
| 1492 |
+
branch_asym_ids = _get_branch_scheme_col('asym_id')
|
| 1493 |
+
branch_auth_seq_ids = _get_branch_scheme_col('pdb_seq_num')
|
| 1494 |
+
branch_pdb_ins_codes = _get_branch_scheme_col('pdb_ins_code')
|
| 1495 |
+
branch_mon_ids = _get_branch_scheme_col('mon_id')
|
| 1496 |
+
branch_auth_asym_id = string_array.remap(
|
| 1497 |
+
branch_asym_ids, mapping=auth_asym_id_by_chain_id, inplace=False
|
| 1498 |
+
)
|
| 1499 |
+
|
| 1500 |
+
if branch_asym_ids.size > 0 and branch_pdb_ins_codes.size == 0:
|
| 1501 |
+
branch_pdb_ins_codes = np.array(['.'] * branch_asym_ids.size, dtype=object)
|
| 1502 |
+
|
| 1503 |
+
# Compute the heterogeneous residue masks as above, this time for ligands.
|
| 1504 |
+
nonpoly_mask, branch_mask = mmcif_utils.selected_ligand_residue_mask(
|
| 1505 |
+
layout=layout,
|
| 1506 |
+
atom_site_label_asym_ids=label_asym_ids[layout.residue_starts()],
|
| 1507 |
+
atom_site_label_seq_ids=label_seq_ids[layout.residue_starts()],
|
| 1508 |
+
atom_site_auth_seq_ids=auth_seq_ids[layout.residue_starts()],
|
| 1509 |
+
atom_site_label_comp_ids=label_comp_ids[layout.residue_starts()],
|
| 1510 |
+
atom_site_pdbx_pdb_ins_codes=pdbx_pdb_ins_codes[layout.residue_starts()],
|
| 1511 |
+
nonpoly_asym_ids=nonpoly_asym_ids,
|
| 1512 |
+
nonpoly_auth_seq_ids=nonpoly_auth_seq_ids,
|
| 1513 |
+
nonpoly_pdb_ins_codes=nonpoly_pdb_ins_codes,
|
| 1514 |
+
nonpoly_mon_ids=nonpoly_mon_ids,
|
| 1515 |
+
branch_asym_ids=branch_asym_ids,
|
| 1516 |
+
branch_auth_seq_ids=branch_auth_seq_ids,
|
| 1517 |
+
branch_pdb_ins_codes=branch_pdb_ins_codes,
|
| 1518 |
+
branch_mon_ids=branch_mon_ids,
|
| 1519 |
+
)
|
| 1520 |
+
|
| 1521 |
+
if not include_water:
|
| 1522 |
+
if nonpoly_mask:
|
| 1523 |
+
nonpoly_mask &= (nonpoly_mon_ids != 'HOH') & (nonpoly_mon_ids != 'DOD')
|
| 1524 |
+
if branch_mask:
|
| 1525 |
+
# Fix for bad mmCIFs that have water in the branch scheme table.
|
| 1526 |
+
branch_mask &= (branch_mon_ids != 'HOH') & (branch_mon_ids != 'DOD')
|
| 1527 |
+
|
| 1528 |
+
string_array.remap(
|
| 1529 |
+
pdbx_pdb_ins_codes, mapping=_INSERTION_CODE_REMAP, inplace=True
|
| 1530 |
+
)
|
| 1531 |
+
string_array.remap(
|
| 1532 |
+
nonpoly_pdb_ins_codes, mapping=_INSERTION_CODE_REMAP, inplace=True
|
| 1533 |
+
)
|
| 1534 |
+
string_array.remap(
|
| 1535 |
+
branch_pdb_ins_codes, mapping=_INSERTION_CODE_REMAP, inplace=True
|
| 1536 |
+
)
|
| 1537 |
+
|
| 1538 |
+
def _ligand_residue_ids(chain_ids: np.ndarray) -> np.ndarray:
|
| 1539 |
+
"""Computes internal residue ID for ligand residues that don't have it."""
|
| 1540 |
+
|
| 1541 |
+
# E.g. chain_ids=[A, A, A, B, C, C, D, D, D] -> [1, 2, 3, 1, 1, 2, 1, 2, 3].
|
| 1542 |
+
indices = np.arange(chain_ids.size, dtype=np.int32)
|
| 1543 |
+
return (indices + 1) - np.maximum.accumulate(
|
| 1544 |
+
indices * (chain_ids != np.roll(chain_ids, 1))
|
| 1545 |
+
)
|
| 1546 |
+
|
| 1547 |
+
branch_residue_ids = _ligand_residue_ids(branch_asym_ids[branch_mask])
|
| 1548 |
+
nonpoly_residue_ids = _ligand_residue_ids(nonpoly_asym_ids[nonpoly_mask])
|
| 1549 |
+
|
| 1550 |
+
chain_res_builder.add_residues(
|
| 1551 |
+
chain_ids=branch_asym_ids[branch_mask],
|
| 1552 |
+
chain_auth_asym_ids=branch_auth_asym_id[branch_mask],
|
| 1553 |
+
res_ids=branch_residue_ids,
|
| 1554 |
+
res_names=branch_mon_ids[branch_mask],
|
| 1555 |
+
res_auth_seq_ids=branch_auth_seq_ids[branch_mask],
|
| 1556 |
+
res_ins_codes=branch_pdb_ins_codes[branch_mask],
|
| 1557 |
+
)
|
| 1558 |
+
|
| 1559 |
+
chain_res_builder.add_residues(
|
| 1560 |
+
chain_ids=nonpoly_asym_ids[nonpoly_mask],
|
| 1561 |
+
chain_auth_asym_ids=nonpoly_auth_asym_id[nonpoly_mask],
|
| 1562 |
+
res_ids=nonpoly_residue_ids,
|
| 1563 |
+
res_names=nonpoly_mon_ids[nonpoly_mask],
|
| 1564 |
+
res_auth_seq_ids=nonpoly_auth_seq_ids[nonpoly_mask],
|
| 1565 |
+
res_ins_codes=nonpoly_pdb_ins_codes[nonpoly_mask],
|
| 1566 |
+
)
|
| 1567 |
+
|
| 1568 |
+
chains = chain_res_builder.make_chains_table()
|
| 1569 |
+
residues = chain_res_builder.make_residues_table()
|
| 1570 |
+
|
| 1571 |
+
# Construct foreign residue keys for the atoms table.
|
| 1572 |
+
res_ends = np.array(layout.residues(), dtype=np.int32)
|
| 1573 |
+
res_starts = np.array(layout.residue_starts(), dtype=np.int32)
|
| 1574 |
+
res_lengths = res_ends - res_starts
|
| 1575 |
+
|
| 1576 |
+
# Check just for HOH, DOD can be part e.g. of hydroxycysteine.
|
| 1577 |
+
if include_water:
|
| 1578 |
+
res_chain_types = chains.apply_array_to_column(
|
| 1579 |
+
column_name='type', arr=residues.chain_key
|
| 1580 |
+
)
|
| 1581 |
+
water_mask = res_chain_types != mmcif_names.WATER
|
| 1582 |
+
if 'HOH' in set(residues.name[water_mask]):
|
| 1583 |
+
raise ValueError('Bad mmCIF file: non-water entity has water molecules.')
|
| 1584 |
+
else:
|
| 1585 |
+
# Include resolved and unresolved residues.
|
| 1586 |
+
if 'HOH' in set(residues.name) | set(label_comp_ids[res_starts]):
|
| 1587 |
+
raise ValueError('Bad mmCIF file: non-water entity has water molecules.')
|
| 1588 |
+
|
| 1589 |
+
atom_chain_key = string_array.remap(
|
| 1590 |
+
label_asym_ids, mapping=chain_res_builder.chain_key_by_chain_id
|
| 1591 |
+
).astype(int)
|
| 1592 |
+
|
| 1593 |
+
# If any of the residue lookups failed, the mmCIF is corrupted.
|
| 1594 |
+
try:
|
| 1595 |
+
atom_res_key_per_res = string_array.remap_multiple(
|
| 1596 |
+
(
|
| 1597 |
+
label_asym_ids[res_starts],
|
| 1598 |
+
auth_seq_ids[res_starts],
|
| 1599 |
+
label_comp_ids[res_starts],
|
| 1600 |
+
pdbx_pdb_ins_codes[res_starts],
|
| 1601 |
+
),
|
| 1602 |
+
mapping=chain_res_builder.key_for_res,
|
| 1603 |
+
)
|
| 1604 |
+
except KeyError as e:
|
| 1605 |
+
raise ValueError(
|
| 1606 |
+
'Lookup for the following atom from the _atom_site table failed: '
|
| 1607 |
+
f'(label_asym_id, auth_seq_id, res_name, ins_code)={e}. This typically '
|
| 1608 |
+
'indicates that the _pdbx_poly_seq_scheme, _pdbx_nonpoly_scheme, or '
|
| 1609 |
+
'_pdbx_branch_scheme tables do not have data for all residues present '
|
| 1610 |
+
'in the _atom_site table. It could also be due to a known issue with '
|
| 1611 |
+
'a small number of multi-model mmCIFs.'
|
| 1612 |
+
) from e
|
| 1613 |
+
|
| 1614 |
+
# The residue ID will be shared for all atoms within that residue.
|
| 1615 |
+
atom_res_key = np.repeat(atom_res_key_per_res, repeats=res_lengths)
|
| 1616 |
+
|
| 1617 |
+
if fix_mse_residues:
|
| 1618 |
+
met_residues_mask = (residues.name == 'MET')[atom_res_key]
|
| 1619 |
+
unfixed_mse_selenium_mask = met_residues_mask & (label_atom_ids == 'SE')
|
| 1620 |
+
label_atom_ids[unfixed_mse_selenium_mask] = 'SD'
|
| 1621 |
+
type_symbols[unfixed_mse_selenium_mask] = 'S'
|
| 1622 |
+
|
| 1623 |
+
atoms = structure_tables.Atoms(
|
| 1624 |
+
key=atom_site_first_model,
|
| 1625 |
+
chain_key=atom_chain_key,
|
| 1626 |
+
res_key=atom_res_key,
|
| 1627 |
+
name=label_atom_ids,
|
| 1628 |
+
element=type_symbols,
|
| 1629 |
+
x=atom_x,
|
| 1630 |
+
y=atom_y,
|
| 1631 |
+
z=atom_z,
|
| 1632 |
+
b_factor=atom_b_factor,
|
| 1633 |
+
occupancy=atom_occupancy,
|
| 1634 |
+
)
|
| 1635 |
+
|
| 1636 |
+
return chains, residues, atoms
|
| 1637 |
+
|
| 1638 |
+
|
| 1639 |
+
def from_atom_arrays(
|
| 1640 |
+
*,
|
| 1641 |
+
res_id: np.ndarray,
|
| 1642 |
+
name: str = 'unset',
|
| 1643 |
+
release_date: datetime.date | None = None,
|
| 1644 |
+
resolution: float | None = None,
|
| 1645 |
+
structure_method: str | None = None,
|
| 1646 |
+
all_residues: Mapping[str, Sequence[tuple[str, int]]] | None = None,
|
| 1647 |
+
bioassembly_data: bioassemblies.BioassemblyData | None = None,
|
| 1648 |
+
chemical_components_data: (
|
| 1649 |
+
struc_chem_comps.ChemicalComponentsData | None
|
| 1650 |
+
) = None,
|
| 1651 |
+
bond_table: structure_tables.Bonds | None = None,
|
| 1652 |
+
chain_id: np.ndarray | None = None,
|
| 1653 |
+
chain_type: np.ndarray | None = None,
|
| 1654 |
+
res_name: np.ndarray | None = None,
|
| 1655 |
+
atom_key: np.ndarray | None = None,
|
| 1656 |
+
atom_name: np.ndarray | None = None,
|
| 1657 |
+
atom_element: np.ndarray | None = None,
|
| 1658 |
+
atom_x: np.ndarray | None = None,
|
| 1659 |
+
atom_y: np.ndarray | None = None,
|
| 1660 |
+
atom_z: np.ndarray | None = None,
|
| 1661 |
+
atom_b_factor: np.ndarray | None = None,
|
| 1662 |
+
atom_occupancy: np.ndarray | None = None,
|
| 1663 |
+
) -> structure.Structure:
|
| 1664 |
+
"""Returns a Structure constructed from atom array level data.
|
| 1665 |
+
|
| 1666 |
+
All fields except name and, res_id are optional, all array fields consist of a
|
| 1667 |
+
value for each atom in the structure - so residue and chain values should hold
|
| 1668 |
+
the same value for each atom in the chain or residue. Fields which are not
|
| 1669 |
+
defined are filled with default values.
|
| 1670 |
+
|
| 1671 |
+
Validation is performed by the Structure constructor where possible - but
|
| 1672 |
+
author_naming scheme and all_residues must be checked in this function.
|
| 1673 |
+
|
| 1674 |
+
It is not possible to construct structures with chains that do not contain
|
| 1675 |
+
any resolved residues using this function. If this is necessary, use the
|
| 1676 |
+
structure.Structure constructor directly.
|
| 1677 |
+
|
| 1678 |
+
Args:
|
| 1679 |
+
res_id: Integer array of shape [num_atom]. The unique residue identifier for
|
| 1680 |
+
each residue. mmCIF field - _atom_site.label_seq_id.
|
| 1681 |
+
name: The name of the structure. E.g. a PDB ID.
|
| 1682 |
+
release_date: The release date of the structure as a `datetime.date`.
|
| 1683 |
+
resolution: The resolution of the structure in Angstroms.
|
| 1684 |
+
structure_method: The method used to solve this structure's coordinates.
|
| 1685 |
+
all_residues: An optional mapping from each chain ID (i.e. label_asym_id) to
|
| 1686 |
+
a sequence of (label_comp_id, label_seq_id) tuples, one per residue. This
|
| 1687 |
+
can contain residues that aren't present in the atom arrays. This is
|
| 1688 |
+
common in experimental data where some residues are not resolved but are
|
| 1689 |
+
known to be present.
|
| 1690 |
+
bioassembly_data: An optional instance of bioassembly.BioassemblyData. If
|
| 1691 |
+
present then a new Structure representing a specific bioassembly can be
|
| 1692 |
+
extracted using `Structure.generate_bioassembly(assembly_id)`.
|
| 1693 |
+
chemical_components_data: An optional instance of ChemicalComponentsData.
|
| 1694 |
+
Its content will be used for providing metadata about chemical components
|
| 1695 |
+
in this Structure instance. If not specified information will be retrieved
|
| 1696 |
+
from the standard chemical component dictionary (CCD, for more details see
|
| 1697 |
+
https://www.wwpdb.org/data/ccd).
|
| 1698 |
+
bond_table: A table representing manually-specified bonds. This corresponds
|
| 1699 |
+
to the _struct_conn table in an mmCIF. Atoms are identified by their key,
|
| 1700 |
+
as specified by the atom_key column. If this table is provided then the
|
| 1701 |
+
atom_key column must also be defined.
|
| 1702 |
+
chain_id: String array of shape [num_atom] of unique chain identifiers.
|
| 1703 |
+
mmCIF field - _atom_site.label_asym_id.
|
| 1704 |
+
chain_type: String array of shape [num_atom]. The molecular type of the
|
| 1705 |
+
current chain (e.g. polyribonucleotide). mmCIF field - _entity_poly.type
|
| 1706 |
+
OR _entity.type (for non-polymers).
|
| 1707 |
+
res_name: String array of shape [num_atom].. The name of each residue,
|
| 1708 |
+
typically a 3 letter string for polypeptides or 1-2 letter strings for
|
| 1709 |
+
polynucleotides. mmCIF field - _atom_site.label_comp_id.
|
| 1710 |
+
atom_key: A unique sorted integer array, used only by the bonds table to
|
| 1711 |
+
identify the atoms participating in each bond. If the bonds table is
|
| 1712 |
+
specified then this column must be non-None.
|
| 1713 |
+
atom_name: String array of shape [num_atom]. The name of each atom (e.g CA,
|
| 1714 |
+
O2', etc.). mmCIF field - _atom_site.label_atom_id.
|
| 1715 |
+
atom_element: String array of shape [num_atom]. The element type of each
|
| 1716 |
+
atom (e.g. C, O, N, etc.). mmCIF field - _atom_site.type_symbol.
|
| 1717 |
+
atom_x: Float array of shape [..., num_atom] of atom x coordinates. May have
|
| 1718 |
+
arbitrary leading dimensions, provided that these are consistent across
|
| 1719 |
+
all coordinate fields.
|
| 1720 |
+
atom_y: Float array of shape [..., num_atom] of atom y coordinates. May have
|
| 1721 |
+
arbitrary leading dimensions, provided that these are consistent across
|
| 1722 |
+
all coordinate fields.
|
| 1723 |
+
atom_z: Float array of shape [..., num_atom] of atom z coordinates. May have
|
| 1724 |
+
arbitrary leading dimensions, provided that these are consistent across
|
| 1725 |
+
all coordinate fields.
|
| 1726 |
+
atom_b_factor: Float array of shape [..., num_atom] or [num_atom] of atom
|
| 1727 |
+
b-factors or equivalent. If there are no extra leading dimensions then
|
| 1728 |
+
these values are assumed to apply to all coordinates for a given atom. If
|
| 1729 |
+
there are leading dimensions then these must match those used by the
|
| 1730 |
+
coordinate fields.
|
| 1731 |
+
atom_occupancy: Float array of shape [..., num_atom] or [num_atom] of atom
|
| 1732 |
+
occupancies or equivalent. If there are no extra leading dimensions then
|
| 1733 |
+
these values are assumed to apply to all coordinates for a given atom. If
|
| 1734 |
+
there are leading dimensions then these must match those used by the
|
| 1735 |
+
coordinate fields.
|
| 1736 |
+
"""
|
| 1737 |
+
|
| 1738 |
+
atoms, residues, chains = structure_tables.tables_from_atom_arrays(
|
| 1739 |
+
res_id=res_id,
|
| 1740 |
+
all_residues=all_residues,
|
| 1741 |
+
chain_id=chain_id,
|
| 1742 |
+
chain_type=chain_type,
|
| 1743 |
+
res_name=res_name,
|
| 1744 |
+
atom_key=atom_key,
|
| 1745 |
+
atom_name=atom_name,
|
| 1746 |
+
atom_element=atom_element,
|
| 1747 |
+
atom_x=atom_x,
|
| 1748 |
+
atom_y=atom_y,
|
| 1749 |
+
atom_z=atom_z,
|
| 1750 |
+
atom_b_factor=atom_b_factor,
|
| 1751 |
+
atom_occupancy=atom_occupancy,
|
| 1752 |
+
)
|
| 1753 |
+
|
| 1754 |
+
return structure.Structure(
|
| 1755 |
+
name=name,
|
| 1756 |
+
release_date=release_date,
|
| 1757 |
+
resolution=resolution,
|
| 1758 |
+
structure_method=structure_method,
|
| 1759 |
+
bioassembly_data=bioassembly_data,
|
| 1760 |
+
chemical_components_data=chemical_components_data,
|
| 1761 |
+
atoms=atoms,
|
| 1762 |
+
chains=chains,
|
| 1763 |
+
residues=residues,
|
| 1764 |
+
bonds=bond_table or structure_tables.Bonds.make_empty(),
|
| 1765 |
+
)
|
| 1766 |
+
|
| 1767 |
+
|
| 1768 |
+
def _guess_entity_type(
|
| 1769 |
+
chain_residues: Collection[str], atom_types: Collection[str]
|
| 1770 |
+
) -> str:
|
| 1771 |
+
"""Guess the entity type (polymer/non-polymer/water) based on residues/atoms.
|
| 1772 |
+
|
| 1773 |
+
We treat both arguments as unordered collections since we care only whether
|
| 1774 |
+
all elements satisfy come conditions. The chain_residues can be either
|
| 1775 |
+
grouped by residue (length num_res), or it can be raw (length num_atoms).
|
| 1776 |
+
Atom type is unique for each atom in a residue, so don't group atom_types.
|
| 1777 |
+
|
| 1778 |
+
Args:
|
| 1779 |
+
chain_residues: A sequence of full residue name (1-letter for DNA, 2-letters
|
| 1780 |
+
for RNA, 3 for protein). The _atom_site.label_comp_id column in mmCIF.
|
| 1781 |
+
atom_types: Atom type: ATOM or HETATM. The _atom_site.group_PDB column in
|
| 1782 |
+
mmCIF.
|
| 1783 |
+
|
| 1784 |
+
Returns:
|
| 1785 |
+
One of polymer/non-polymer/water based on the following criteria:
|
| 1786 |
+
* If all atoms are HETATMs and all residues are water -> water.
|
| 1787 |
+
* If all atoms are HETATMs and not all residues are water -> non-polymer.
|
| 1788 |
+
* Otherwise -> polymer.
|
| 1789 |
+
"""
|
| 1790 |
+
if not chain_residues or not atom_types:
|
| 1791 |
+
raise ValueError(
|
| 1792 |
+
f'chain_residues (len {len(chain_residues)}) and atom_types (len '
|
| 1793 |
+
f'{len(atom_types)}) must be both non-empty. Got: {chain_residues=} '
|
| 1794 |
+
f'and {atom_types=}'
|
| 1795 |
+
)
|
| 1796 |
+
|
| 1797 |
+
if all(a == 'HETATM' for a in atom_types):
|
| 1798 |
+
if all(c in residue_names.WATER_TYPES for c in chain_residues):
|
| 1799 |
+
return mmcif_names.WATER
|
| 1800 |
+
return mmcif_names.NON_POLYMER_CHAIN
|
| 1801 |
+
return mmcif_names.POLYMER_CHAIN
|
flax_model/alphafold3/structure/sterics.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
"""Functions relating to spatial locations of atoms within a structure."""
|
| 4 |
+
|
| 5 |
+
from collections.abc import Collection, Sequence
|
| 6 |
+
|
| 7 |
+
from flax_model.alphafold3 import structure
|
| 8 |
+
from flax_model.alphafold3.structure import mmcif
|
| 9 |
+
import numpy as np
|
| 10 |
+
import scipy
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def _make_atom_has_clash_mask(
|
| 14 |
+
kd_query_result: np.ndarray,
|
| 15 |
+
struc: structure.Structure,
|
| 16 |
+
ignore_chains: Collection[str],
|
| 17 |
+
) -> np.ndarray:
|
| 18 |
+
"""Returns a boolean NumPy array representing whether each atom has a clash.
|
| 19 |
+
|
| 20 |
+
Args:
|
| 21 |
+
kd_query_result: NumPy array containing N-atoms arrays, each array
|
| 22 |
+
containing indices to atoms that clash with the N'th atom.
|
| 23 |
+
struc: Structure over which clashes were detected.
|
| 24 |
+
ignore_chains: Collection of chains that should not be considered clashing.
|
| 25 |
+
A boolean NumPy array of length N atoms.
|
| 26 |
+
"""
|
| 27 |
+
atom_is_clashing = np.zeros((struc.num_atoms,), dtype=bool)
|
| 28 |
+
for atom_index, clashes in enumerate(kd_query_result):
|
| 29 |
+
chain_i = struc.chain_id[atom_index]
|
| 30 |
+
if chain_i in ignore_chains:
|
| 31 |
+
continue
|
| 32 |
+
islig_i = struc.is_ligand_mask[atom_index]
|
| 33 |
+
for clashing_atom_index in clashes:
|
| 34 |
+
chain_c = struc.chain_id[clashing_atom_index]
|
| 35 |
+
if chain_c in ignore_chains:
|
| 36 |
+
continue
|
| 37 |
+
islig_c = struc.is_ligand_mask[clashing_atom_index]
|
| 38 |
+
if (
|
| 39 |
+
clashing_atom_index == atom_index
|
| 40 |
+
or chain_i == chain_c
|
| 41 |
+
or islig_i != islig_c
|
| 42 |
+
):
|
| 43 |
+
# Ignore clashes within chain or between ligand and polymer.
|
| 44 |
+
continue
|
| 45 |
+
atom_is_clashing[atom_index] = True
|
| 46 |
+
return atom_is_clashing
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def find_clashing_chains(
|
| 50 |
+
struc: structure.Structure,
|
| 51 |
+
clash_thresh_angstrom: float = 1.7,
|
| 52 |
+
clash_thresh_fraction: float = 0.3,
|
| 53 |
+
) -> Sequence[str]:
|
| 54 |
+
"""Finds chains that clash with others.
|
| 55 |
+
|
| 56 |
+
Clashes are defined by polymer backbone atoms and all ligand atoms.
|
| 57 |
+
Ligand-polymer clashes are not dropped.
|
| 58 |
+
|
| 59 |
+
Will not find clashes if all coordinates are 0. Coordinates are all 0s if
|
| 60 |
+
the structure is generated from sequences only, as done for inference in
|
| 61 |
+
dendro for example.
|
| 62 |
+
|
| 63 |
+
Args:
|
| 64 |
+
struc: The structure defining the chains and atom positions.
|
| 65 |
+
clash_thresh_angstrom: Below this distance, atoms are considered clashing.
|
| 66 |
+
clash_thresh_fraction: Chains with more than this fraction of their atoms
|
| 67 |
+
considered clashing will be dropped. This value should be in the range (0,
|
| 68 |
+
1].
|
| 69 |
+
|
| 70 |
+
Returns:
|
| 71 |
+
A sequence of chain ids for chains that clash.
|
| 72 |
+
|
| 73 |
+
Raises:
|
| 74 |
+
ValueError: If `clash_thresh_fraction` is not in range (0,1].
|
| 75 |
+
"""
|
| 76 |
+
if not 0 < clash_thresh_fraction <= 1:
|
| 77 |
+
raise ValueError('clash_thresh_fraction must be in range (0,1]')
|
| 78 |
+
|
| 79 |
+
struc_backbone = struc.filter_polymers_to_single_atom_per_res()
|
| 80 |
+
if struc_backbone.num_chains == 0:
|
| 81 |
+
return []
|
| 82 |
+
|
| 83 |
+
# If the coordinates are all 0, do not search for clashes.
|
| 84 |
+
if not np.any(struc_backbone.coords):
|
| 85 |
+
return []
|
| 86 |
+
|
| 87 |
+
coord_kdtree = scipy.spatial.cKDTree(struc_backbone.coords)
|
| 88 |
+
|
| 89 |
+
# For each atom coordinate, find all atoms within the clash thresh radius.
|
| 90 |
+
clashing_per_atom = coord_kdtree.query_ball_point(
|
| 91 |
+
struc_backbone.coords, r=clash_thresh_angstrom
|
| 92 |
+
)
|
| 93 |
+
chain_ids = struc_backbone.chains
|
| 94 |
+
if struc_backbone.atom_occupancy is not None:
|
| 95 |
+
chain_occupancy = np.array([
|
| 96 |
+
np.mean(struc_backbone.atom_occupancy[start:end])
|
| 97 |
+
for start, end in struc_backbone.iter_chain_ranges()
|
| 98 |
+
])
|
| 99 |
+
else:
|
| 100 |
+
chain_occupancy = None
|
| 101 |
+
|
| 102 |
+
# Remove chains until no more significant clashing.
|
| 103 |
+
chains_to_remove = set()
|
| 104 |
+
for _ in range(len(chain_ids)):
|
| 105 |
+
# Calculate maximally clashing.
|
| 106 |
+
atom_has_clash = _make_atom_has_clash_mask(
|
| 107 |
+
clashing_per_atom, struc_backbone, chains_to_remove
|
| 108 |
+
)
|
| 109 |
+
clashes_per_chain = np.array([
|
| 110 |
+
atom_has_clash[start:end].mean()
|
| 111 |
+
for start, end in struc_backbone.iter_chain_ranges()
|
| 112 |
+
])
|
| 113 |
+
max_clash = np.max(clashes_per_chain)
|
| 114 |
+
if max_clash <= clash_thresh_fraction:
|
| 115 |
+
# None of the remaining chains exceed the clash fraction threshold, so
|
| 116 |
+
# we can exit.
|
| 117 |
+
break
|
| 118 |
+
|
| 119 |
+
# Greedily remove worst with the lowest occupancy.
|
| 120 |
+
most_clashes = np.nonzero(clashes_per_chain == max_clash)[0]
|
| 121 |
+
if chain_occupancy is not None:
|
| 122 |
+
occupancy_clashing = chain_occupancy[most_clashes]
|
| 123 |
+
last_lowest_occupancy = (
|
| 124 |
+
len(occupancy_clashing) - np.argmin(occupancy_clashing[::-1]) - 1
|
| 125 |
+
)
|
| 126 |
+
worst_and_last = most_clashes[last_lowest_occupancy]
|
| 127 |
+
else:
|
| 128 |
+
worst_and_last = most_clashes[-1]
|
| 129 |
+
|
| 130 |
+
chains_to_remove.add(chain_ids[worst_and_last])
|
| 131 |
+
|
| 132 |
+
return sorted(chains_to_remove, key=mmcif.str_id_to_int_id)
|
flax_model/alphafold3/structure/structure.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/structure/structure_tables.py
ADDED
|
@@ -0,0 +1,811 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
"""Table implementations for the Structure class."""
|
| 4 |
+
|
| 5 |
+
import collections
|
| 6 |
+
from collections.abc import Mapping, Sequence
|
| 7 |
+
import dataclasses
|
| 8 |
+
import functools
|
| 9 |
+
import itertools
|
| 10 |
+
import typing
|
| 11 |
+
from typing import Any, ClassVar, Self
|
| 12 |
+
|
| 13 |
+
from flax_model.alphafold3.constants import mmcif_names
|
| 14 |
+
from flax_model.alphafold3.constants import residue_names
|
| 15 |
+
from flax_model.alphafold3.cpp import aggregation
|
| 16 |
+
from flax_model.alphafold3.cpp import string_array
|
| 17 |
+
from flax_model.alphafold3.structure import bonds as bonds_module
|
| 18 |
+
from flax_model.alphafold3.structure import mmcif
|
| 19 |
+
from flax_model.alphafold3.structure import table
|
| 20 |
+
import numpy as np
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
Bonds = bonds_module.Bonds
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def _residue_name_to_record_name(
|
| 27 |
+
residue_name: np.ndarray,
|
| 28 |
+
polymer_mask: np.ndarray,
|
| 29 |
+
) -> np.ndarray:
|
| 30 |
+
"""Returns record names (ATOM/HETATM) given residue names and polymer mask."""
|
| 31 |
+
record_name = np.array(['HETATM'] * len(residue_name), dtype=object)
|
| 32 |
+
record_name[polymer_mask] = string_array.remap(
|
| 33 |
+
residue_name[polymer_mask],
|
| 34 |
+
mapping={r: 'ATOM' for r in residue_names.STANDARD_POLYMER_TYPES},
|
| 35 |
+
default_value='HETATM',
|
| 36 |
+
)
|
| 37 |
+
return record_name
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
| 41 |
+
class AuthorNamingScheme:
|
| 42 |
+
"""A mapping from internal values to author values in a mmCIF.
|
| 43 |
+
|
| 44 |
+
Fields:
|
| 45 |
+
auth_asym_id: A mapping from label_asym_id to auth_asym_id.
|
| 46 |
+
auth_seq_id: A mapping from label_asym_id to a mapping from
|
| 47 |
+
label_seq_id to auth_seq_id.
|
| 48 |
+
insertion_code: A mapping from label_asym_id to a mapping from
|
| 49 |
+
label_seq_id to insertion codes.
|
| 50 |
+
entity_id: A mapping from label_asym_id to _entity.id.
|
| 51 |
+
entity_desc: A mapping from _entity.id to _entity.pdbx_description.
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
auth_asym_id: Mapping[str, str]
|
| 55 |
+
auth_seq_id: Mapping[str, Mapping[int, str]]
|
| 56 |
+
insertion_code: Mapping[str, Mapping[int, str | None]]
|
| 57 |
+
entity_id: Mapping[str, str]
|
| 58 |
+
entity_desc: Mapping[str, str]
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def _default(
|
| 62 |
+
candidate_value: np.ndarray | None, default_value: Sequence[Any], dtype: Any
|
| 63 |
+
) -> np.ndarray:
|
| 64 |
+
if candidate_value is None:
|
| 65 |
+
return np.array(default_value, dtype=dtype)
|
| 66 |
+
return np.array(candidate_value, dtype=dtype)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
| 70 |
+
class Atoms(table.Table):
|
| 71 |
+
"""Table of atoms in a Structure."""
|
| 72 |
+
|
| 73 |
+
chain_key: np.ndarray
|
| 74 |
+
res_key: np.ndarray
|
| 75 |
+
name: np.ndarray
|
| 76 |
+
element: np.ndarray
|
| 77 |
+
x: np.ndarray
|
| 78 |
+
y: np.ndarray
|
| 79 |
+
z: np.ndarray
|
| 80 |
+
b_factor: np.ndarray
|
| 81 |
+
occupancy: np.ndarray
|
| 82 |
+
multimodel_cols: ClassVar[tuple[str, ...]] = (
|
| 83 |
+
'x',
|
| 84 |
+
'y',
|
| 85 |
+
'z',
|
| 86 |
+
'b_factor',
|
| 87 |
+
'occupancy',
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
def __post_init__(self):
|
| 91 |
+
# Validates that the atom coordinates, b-factors and occupancies are finite.
|
| 92 |
+
for column_name in ('x', 'y', 'z', 'b_factor', 'occupancy'):
|
| 93 |
+
column = self.get_column(column_name)
|
| 94 |
+
if not np.isfinite(column).all():
|
| 95 |
+
raise ValueError(
|
| 96 |
+
f'Column {column_name} must not contain NaN/inf values.'
|
| 97 |
+
)
|
| 98 |
+
# super().__post_init__() can't be used as that causes the following error:
|
| 99 |
+
# TypeError: super(type, obj): obj must be an instance or subtype of type
|
| 100 |
+
super(Atoms, self).__post_init__()
|
| 101 |
+
|
| 102 |
+
@classmethod
|
| 103 |
+
def make_empty(cls) -> Self:
|
| 104 |
+
return cls(
|
| 105 |
+
key=np.array([], dtype=np.int64),
|
| 106 |
+
chain_key=np.array([], dtype=np.int64),
|
| 107 |
+
res_key=np.array([], dtype=np.int64),
|
| 108 |
+
name=np.array([], dtype=object),
|
| 109 |
+
element=np.array([], dtype=object),
|
| 110 |
+
x=np.array([], dtype=np.float32),
|
| 111 |
+
y=np.array([], dtype=np.float32),
|
| 112 |
+
z=np.array([], dtype=np.float32),
|
| 113 |
+
b_factor=np.array([], dtype=np.float32),
|
| 114 |
+
occupancy=np.array([], dtype=np.float32),
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
@classmethod
|
| 118 |
+
def from_defaults(
|
| 119 |
+
cls,
|
| 120 |
+
*,
|
| 121 |
+
chain_key: np.ndarray,
|
| 122 |
+
res_key: np.ndarray,
|
| 123 |
+
key: np.ndarray | None = None,
|
| 124 |
+
name: np.ndarray | None = None,
|
| 125 |
+
element: np.ndarray | None = None,
|
| 126 |
+
x: np.ndarray | None = None,
|
| 127 |
+
y: np.ndarray | None = None,
|
| 128 |
+
z: np.ndarray | None = None,
|
| 129 |
+
b_factor: np.ndarray | None = None,
|
| 130 |
+
occupancy: np.ndarray | None = None,
|
| 131 |
+
) -> Self:
|
| 132 |
+
"""Create an Atoms table with minimal user inputs."""
|
| 133 |
+
num_atoms = len(chain_key)
|
| 134 |
+
if not num_atoms:
|
| 135 |
+
return cls.make_empty()
|
| 136 |
+
return Atoms(
|
| 137 |
+
chain_key=chain_key,
|
| 138 |
+
res_key=res_key,
|
| 139 |
+
key=_default(key, np.arange(num_atoms), np.int64),
|
| 140 |
+
name=_default(name, ['?'] * num_atoms, object),
|
| 141 |
+
element=_default(element, ['?'] * num_atoms, object),
|
| 142 |
+
x=_default(x, [0.0] * num_atoms, np.float32),
|
| 143 |
+
y=_default(y, [0.0] * num_atoms, np.float32),
|
| 144 |
+
z=_default(z, [0.0] * num_atoms, np.float32),
|
| 145 |
+
b_factor=_default(b_factor, [0.0] * num_atoms, np.float32),
|
| 146 |
+
occupancy=_default(occupancy, [1.0] * num_atoms, np.float32),
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
def get_value_by_index(
|
| 150 |
+
self, column_name: str, index: int
|
| 151 |
+
) -> table.TableEntry | np.ndarray:
|
| 152 |
+
if column_name in self.multimodel_cols:
|
| 153 |
+
return self.get_column(column_name)[..., index]
|
| 154 |
+
else:
|
| 155 |
+
return self.get_column(column_name)[index]
|
| 156 |
+
|
| 157 |
+
def copy_and_update_coords(self, coords: np.ndarray) -> Self:
|
| 158 |
+
"""Returns a copy with the x, y and z columns updated."""
|
| 159 |
+
if coords.shape[-1] != 3:
|
| 160 |
+
raise ValueError(
|
| 161 |
+
f'Expecting 3-dimensional coordinates, got {coords.shape}'
|
| 162 |
+
)
|
| 163 |
+
return typing.cast(
|
| 164 |
+
Atoms,
|
| 165 |
+
self.copy_and_update(
|
| 166 |
+
x=coords[..., 0], y=coords[..., 1], z=coords[..., 2]
|
| 167 |
+
),
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
+
@property
|
| 171 |
+
def shape(self) -> tuple[int, ...]:
|
| 172 |
+
return self.x.shape
|
| 173 |
+
|
| 174 |
+
@property
|
| 175 |
+
def ndim(self) -> int:
|
| 176 |
+
return len(self.shape)
|
| 177 |
+
|
| 178 |
+
@functools.cached_property
|
| 179 |
+
def num_models(self) -> int:
|
| 180 |
+
"""The number of models of this Structure."""
|
| 181 |
+
leading_dims = self.shape[:-1]
|
| 182 |
+
match leading_dims:
|
| 183 |
+
case ():
|
| 184 |
+
return 1
|
| 185 |
+
case (single_leading_dim_size,):
|
| 186 |
+
return single_leading_dim_size
|
| 187 |
+
case _:
|
| 188 |
+
raise ValueError(
|
| 189 |
+
'num_models not defined for atom tables with more than one '
|
| 190 |
+
'leading dimension.'
|
| 191 |
+
)
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
| 195 |
+
class Residues(table.Table):
|
| 196 |
+
"""Table of residues in a Structure."""
|
| 197 |
+
|
| 198 |
+
chain_key: np.ndarray
|
| 199 |
+
id: np.ndarray
|
| 200 |
+
name: np.ndarray
|
| 201 |
+
auth_seq_id: np.ndarray
|
| 202 |
+
insertion_code: np.ndarray
|
| 203 |
+
|
| 204 |
+
@classmethod
|
| 205 |
+
def make_empty(cls) -> Self:
|
| 206 |
+
return cls(
|
| 207 |
+
key=np.array([], dtype=np.int64),
|
| 208 |
+
chain_key=np.array([], dtype=np.int64),
|
| 209 |
+
id=np.array([], dtype=np.int32),
|
| 210 |
+
name=np.array([], dtype=object),
|
| 211 |
+
auth_seq_id=np.array([], dtype=object),
|
| 212 |
+
insertion_code=np.array([], dtype=object),
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
@classmethod
|
| 216 |
+
def from_defaults(
|
| 217 |
+
cls,
|
| 218 |
+
*,
|
| 219 |
+
id: np.ndarray, # pylint:disable=redefined-builtin
|
| 220 |
+
chain_key: np.ndarray,
|
| 221 |
+
key: np.ndarray | None = None,
|
| 222 |
+
name: np.ndarray | None = None,
|
| 223 |
+
auth_seq_id: np.ndarray | None = None,
|
| 224 |
+
insertion_code: np.ndarray | None = None,
|
| 225 |
+
) -> Self:
|
| 226 |
+
"""Create a Residues table with minimal user inputs."""
|
| 227 |
+
num_res = len(id)
|
| 228 |
+
if not num_res:
|
| 229 |
+
return cls.make_empty()
|
| 230 |
+
return Residues(
|
| 231 |
+
key=_default(key, np.arange(num_res), np.int64),
|
| 232 |
+
id=id,
|
| 233 |
+
chain_key=chain_key,
|
| 234 |
+
name=_default(name, ['UNK'] * num_res, object),
|
| 235 |
+
auth_seq_id=_default(auth_seq_id, id.astype(str), object),
|
| 236 |
+
insertion_code=_default(insertion_code, ['?'] * num_res, object),
|
| 237 |
+
)
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
|
| 241 |
+
class Chains(table.Table):
|
| 242 |
+
"""Table of chains in a Structure."""
|
| 243 |
+
|
| 244 |
+
id: np.ndarray
|
| 245 |
+
type: np.ndarray
|
| 246 |
+
auth_asym_id: np.ndarray
|
| 247 |
+
entity_id: np.ndarray
|
| 248 |
+
entity_desc: np.ndarray
|
| 249 |
+
|
| 250 |
+
@classmethod
|
| 251 |
+
def make_empty(cls) -> Self:
|
| 252 |
+
return cls(
|
| 253 |
+
key=np.array([], dtype=np.int64),
|
| 254 |
+
id=np.array([], dtype=object),
|
| 255 |
+
type=np.array([], dtype=object),
|
| 256 |
+
auth_asym_id=np.array([], dtype=object),
|
| 257 |
+
entity_id=np.array([], dtype=object),
|
| 258 |
+
entity_desc=np.array([], dtype=object),
|
| 259 |
+
)
|
| 260 |
+
|
| 261 |
+
@classmethod
|
| 262 |
+
def from_defaults(
|
| 263 |
+
cls,
|
| 264 |
+
*,
|
| 265 |
+
id: np.ndarray, # pylint:disable=redefined-builtin
|
| 266 |
+
key: np.ndarray | None = None,
|
| 267 |
+
type: np.ndarray | None = None, # pylint:disable=redefined-builtin
|
| 268 |
+
auth_asym_id: np.ndarray | None = None,
|
| 269 |
+
entity_id: np.ndarray | None = None,
|
| 270 |
+
entity_desc: np.ndarray | None = None,
|
| 271 |
+
) -> Self:
|
| 272 |
+
"""Create a Chains table with minimal user inputs."""
|
| 273 |
+
num_chains = len(id)
|
| 274 |
+
if not num_chains:
|
| 275 |
+
return cls.make_empty()
|
| 276 |
+
|
| 277 |
+
return Chains(
|
| 278 |
+
key=_default(key, np.arange(num_chains), np.int64),
|
| 279 |
+
id=id,
|
| 280 |
+
type=_default(type, [mmcif_names.PROTEIN_CHAIN] * num_chains, object),
|
| 281 |
+
auth_asym_id=_default(auth_asym_id, id, object),
|
| 282 |
+
entity_id=_default(
|
| 283 |
+
entity_id, np.arange(1, num_chains + 1).astype(str), object
|
| 284 |
+
),
|
| 285 |
+
entity_desc=_default(entity_desc, ['.'] * num_chains, object),
|
| 286 |
+
)
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
def to_mmcif_sequence_and_entity_tables(
|
| 290 |
+
chains: Chains,
|
| 291 |
+
residues: Residues,
|
| 292 |
+
atom_res_key: np.ndarray,
|
| 293 |
+
) -> Mapping[str, Sequence[str]]:
|
| 294 |
+
"""Returns raw sequence and entity mmCIF tables."""
|
| 295 |
+
raw_mmcif = collections.defaultdict(list)
|
| 296 |
+
chains_by_entity_id = {}
|
| 297 |
+
written_entity_poly_seq_ids = set()
|
| 298 |
+
present_res_keys = set(atom_res_key)
|
| 299 |
+
|
| 300 |
+
# Performance optimisation: Find residue indices for each chain in advance, so
|
| 301 |
+
# that we don't have to do redunant masking work for each chain.
|
| 302 |
+
res_indices_for_chain = aggregation.indices_grouped_by_value(
|
| 303 |
+
residues.chain_key
|
| 304 |
+
)
|
| 305 |
+
|
| 306 |
+
for chain in chains.iterrows():
|
| 307 |
+
# Add all chain information to the _struct_asym table.
|
| 308 |
+
chain_id = chain['id'] # Saves multiple dict lookups.
|
| 309 |
+
auth_asym_id = chain['auth_asym_id']
|
| 310 |
+
entity_id = chain['entity_id']
|
| 311 |
+
chains_by_entity_id.setdefault(entity_id, []).append(chain)
|
| 312 |
+
raw_mmcif['_struct_asym.id'].append(chain_id)
|
| 313 |
+
raw_mmcif['_struct_asym.entity_id'].append(entity_id)
|
| 314 |
+
|
| 315 |
+
res_chain_indices = res_indices_for_chain[chain['key']]
|
| 316 |
+
chain_type = chain['type']
|
| 317 |
+
is_polymer = chain_type in mmcif_names.POLYMER_CHAIN_TYPES
|
| 318 |
+
is_water = chain_type == mmcif_names.WATER
|
| 319 |
+
is_branched = len(res_chain_indices) > 1 and not is_polymer and not is_water
|
| 320 |
+
write_entity_poly_seq = entity_id not in written_entity_poly_seq_ids
|
| 321 |
+
|
| 322 |
+
# Iterate over the individual masked residue table columns, as that doesn't
|
| 323 |
+
# create a copy (only a view), while residues[res_chain_indices] does.
|
| 324 |
+
for res_key, res_name, res_id, pdb_seq_num, res_ins_code in zip(
|
| 325 |
+
residues.key[res_chain_indices],
|
| 326 |
+
residues.name[res_chain_indices],
|
| 327 |
+
residues.id[res_chain_indices],
|
| 328 |
+
residues.auth_seq_id[res_chain_indices],
|
| 329 |
+
residues.insertion_code[res_chain_indices],
|
| 330 |
+
strict=True,
|
| 331 |
+
):
|
| 332 |
+
is_missing = res_key not in present_res_keys
|
| 333 |
+
str_res_id = str(res_id)
|
| 334 |
+
# While atom_site uses "?" for insertion codes, scheme tables use ".".
|
| 335 |
+
ins_code = (res_ins_code or '.').replace('?', '.')
|
| 336 |
+
auth_seq_num = '?' if is_missing else pdb_seq_num
|
| 337 |
+
|
| 338 |
+
if is_polymer:
|
| 339 |
+
raw_mmcif['_pdbx_poly_seq_scheme.asym_id'].append(chain_id)
|
| 340 |
+
raw_mmcif['_pdbx_poly_seq_scheme.entity_id'].append(entity_id)
|
| 341 |
+
raw_mmcif['_pdbx_poly_seq_scheme.seq_id'].append(str_res_id)
|
| 342 |
+
raw_mmcif['_pdbx_poly_seq_scheme.mon_id'].append(res_name)
|
| 343 |
+
raw_mmcif['_pdbx_poly_seq_scheme.pdb_seq_num'].append(pdb_seq_num)
|
| 344 |
+
raw_mmcif['_pdbx_poly_seq_scheme.auth_seq_num'].append(auth_seq_num)
|
| 345 |
+
raw_mmcif['_pdbx_poly_seq_scheme.pdb_strand_id'].append(auth_asym_id)
|
| 346 |
+
raw_mmcif['_pdbx_poly_seq_scheme.pdb_ins_code'].append(ins_code)
|
| 347 |
+
# Structure doesn't support heterogeneous sequences.
|
| 348 |
+
raw_mmcif['_pdbx_poly_seq_scheme.hetero'].append('n')
|
| 349 |
+
if write_entity_poly_seq:
|
| 350 |
+
raw_mmcif['_entity_poly_seq.entity_id'].append(entity_id)
|
| 351 |
+
raw_mmcif['_entity_poly_seq.num'].append(str_res_id)
|
| 352 |
+
raw_mmcif['_entity_poly_seq.mon_id'].append(res_name)
|
| 353 |
+
# Structure doesn't support heterogeneous sequences.
|
| 354 |
+
raw_mmcif['_entity_poly_seq.hetero'].append('n')
|
| 355 |
+
written_entity_poly_seq_ids.add(entity_id)
|
| 356 |
+
elif is_branched:
|
| 357 |
+
raw_mmcif['_pdbx_branch_scheme.asym_id'].append(chain_id)
|
| 358 |
+
raw_mmcif['_pdbx_branch_scheme.entity_id'].append(entity_id)
|
| 359 |
+
raw_mmcif['_pdbx_branch_scheme.mon_id'].append(res_name)
|
| 360 |
+
raw_mmcif['_pdbx_branch_scheme.num'].append(str_res_id)
|
| 361 |
+
raw_mmcif['_pdbx_branch_scheme.pdb_asym_id'].append(auth_asym_id)
|
| 362 |
+
raw_mmcif['_pdbx_branch_scheme.pdb_seq_num'].append(pdb_seq_num)
|
| 363 |
+
raw_mmcif['_pdbx_branch_scheme.auth_asym_id'].append(auth_asym_id)
|
| 364 |
+
raw_mmcif['_pdbx_branch_scheme.auth_seq_num'].append(auth_seq_num)
|
| 365 |
+
raw_mmcif['_pdbx_branch_scheme.pdb_ins_code'].append(ins_code)
|
| 366 |
+
# Structure doesn't support heterogeneous sequences.
|
| 367 |
+
raw_mmcif['_pdbx_branch_scheme.hetero'].append('n')
|
| 368 |
+
else:
|
| 369 |
+
raw_mmcif['_pdbx_nonpoly_scheme.asym_id'].append(chain_id)
|
| 370 |
+
raw_mmcif['_pdbx_nonpoly_scheme.entity_id'].append(entity_id)
|
| 371 |
+
raw_mmcif['_pdbx_nonpoly_scheme.mon_id'].append(res_name)
|
| 372 |
+
raw_mmcif['_pdbx_nonpoly_scheme.pdb_seq_num'].append(pdb_seq_num)
|
| 373 |
+
raw_mmcif['_pdbx_nonpoly_scheme.auth_seq_num'].append(auth_seq_num)
|
| 374 |
+
raw_mmcif['_pdbx_nonpoly_scheme.pdb_strand_id'].append(auth_asym_id)
|
| 375 |
+
raw_mmcif['_pdbx_nonpoly_scheme.pdb_ins_code'].append(ins_code)
|
| 376 |
+
|
| 377 |
+
# Add _entity and _entity_poly tables.
|
| 378 |
+
for entity_id, chains in chains_by_entity_id.items():
|
| 379 |
+
# chains should always be a non-empty list because of how we constructed
|
| 380 |
+
# chains_by_entity_id.
|
| 381 |
+
assert chains
|
| 382 |
+
# All chains for a given entity should have the same type and sequence
|
| 383 |
+
# so we can pick the first one without losing information.
|
| 384 |
+
key_chain = chains[0]
|
| 385 |
+
raw_mmcif['_entity.id'].append(entity_id)
|
| 386 |
+
raw_mmcif['_entity.pdbx_description'].append(key_chain['entity_desc'])
|
| 387 |
+
entity_type = key_chain['type']
|
| 388 |
+
if entity_type not in mmcif_names.POLYMER_CHAIN_TYPES:
|
| 389 |
+
raw_mmcif['_entity.type'].append(entity_type)
|
| 390 |
+
else:
|
| 391 |
+
raw_mmcif['_entity.type'].append('polymer')
|
| 392 |
+
raw_mmcif['_entity_poly.entity_id'].append(entity_id)
|
| 393 |
+
raw_mmcif['_entity_poly.type'].append(entity_type)
|
| 394 |
+
|
| 395 |
+
# _entity_poly.pdbx_strand_id is a comma-separated list of
|
| 396 |
+
# auth_asym_ids that are part of the entity.
|
| 397 |
+
raw_mmcif['_entity_poly.pdbx_strand_id'].append(
|
| 398 |
+
','.join(chain['auth_asym_id'] for chain in chains)
|
| 399 |
+
)
|
| 400 |
+
return raw_mmcif
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
def to_mmcif_atom_site_and_bonds_table(
|
| 404 |
+
*,
|
| 405 |
+
chains: Chains,
|
| 406 |
+
residues: Residues,
|
| 407 |
+
atoms: Atoms,
|
| 408 |
+
bonds: Bonds,
|
| 409 |
+
coords_decimal_places: int,
|
| 410 |
+
) -> Mapping[str, Sequence[str]]:
|
| 411 |
+
"""Returns raw _atom_site and _struct_conn mmCIF tables."""
|
| 412 |
+
raw_mmcif = collections.defaultdict(list)
|
| 413 |
+
# Use [value] * num wherever possible since it is about 10x faster than list
|
| 414 |
+
# comprehension in such cases. Also use f-strings instead of str() - faster.
|
| 415 |
+
total_atoms = atoms.size * atoms.num_models
|
| 416 |
+
raw_mmcif['_atom_site.id'] = [f'{i}' for i in range(1, total_atoms + 1)]
|
| 417 |
+
raw_mmcif['_atom_site.label_alt_id'] = ['.'] * total_atoms
|
| 418 |
+
# Use format_float_array instead of list comprehension for performance.
|
| 419 |
+
raw_mmcif['_atom_site.Cartn_x'] = mmcif.format_float_array(
|
| 420 |
+
values=atoms.x.ravel(), num_decimal_places=coords_decimal_places
|
| 421 |
+
)
|
| 422 |
+
raw_mmcif['_atom_site.Cartn_y'] = mmcif.format_float_array(
|
| 423 |
+
values=atoms.y.ravel(), num_decimal_places=coords_decimal_places
|
| 424 |
+
)
|
| 425 |
+
raw_mmcif['_atom_site.Cartn_z'] = mmcif.format_float_array(
|
| 426 |
+
values=atoms.z.ravel(), num_decimal_places=coords_decimal_places
|
| 427 |
+
)
|
| 428 |
+
|
| 429 |
+
# atoms.b_factor or atoms.occupancy can be flat even when the coordinates have
|
| 430 |
+
# leading dimensions. In this case we tile it to match.
|
| 431 |
+
if atoms.b_factor.ndim == 1:
|
| 432 |
+
atom_b_factor = np.tile(atoms.b_factor, atoms.num_models)
|
| 433 |
+
else:
|
| 434 |
+
atom_b_factor = atoms.b_factor.ravel()
|
| 435 |
+
raw_mmcif['_atom_site.B_iso_or_equiv'] = mmcif.format_float_array(
|
| 436 |
+
values=atom_b_factor, num_decimal_places=2
|
| 437 |
+
)
|
| 438 |
+
|
| 439 |
+
if atoms.occupancy.ndim == 1:
|
| 440 |
+
atom_occupancy = np.tile(atoms.occupancy, atoms.num_models)
|
| 441 |
+
else:
|
| 442 |
+
atom_occupancy = atoms.occupancy.ravel()
|
| 443 |
+
raw_mmcif['_atom_site.occupancy'] = mmcif.format_float_array(
|
| 444 |
+
values=atom_occupancy.ravel(), num_decimal_places=2
|
| 445 |
+
)
|
| 446 |
+
|
| 447 |
+
label_atom_id = atoms.name
|
| 448 |
+
type_symbol = atoms.element
|
| 449 |
+
label_comp_id = residues.apply_array_to_column('name', atoms.res_key)
|
| 450 |
+
label_asym_id = chains.apply_array_to_column('id', atoms.chain_key)
|
| 451 |
+
label_entity_id = chains.apply_array_to_column('entity_id', atoms.chain_key)
|
| 452 |
+
# Performance optimisation: Do the int->str conversion on num_residue-sized,
|
| 453 |
+
# array, then select instead of selecting and then converting.
|
| 454 |
+
label_seq_id = residues.id.astype('str').astype(object)[
|
| 455 |
+
..., residues.index_by_key[atoms.res_key]
|
| 456 |
+
]
|
| 457 |
+
|
| 458 |
+
# _atom_site.label_seq_id is '.' for non-polymers.
|
| 459 |
+
non_polymer_chain_mask = string_array.isin(
|
| 460 |
+
chains.type, mmcif_names.POLYMER_CHAIN_TYPES, invert=True
|
| 461 |
+
)
|
| 462 |
+
non_polymer_chain_keys = chains.key[non_polymer_chain_mask]
|
| 463 |
+
non_polymer_atom_mask = np.isin(atoms.chain_key, non_polymer_chain_keys)
|
| 464 |
+
label_seq_id[non_polymer_atom_mask] = '.'
|
| 465 |
+
|
| 466 |
+
auth_asym_id = chains.apply_array_to_column('auth_asym_id', atoms.chain_key)
|
| 467 |
+
auth_seq_id = residues.apply_array_to_column('auth_seq_id', atoms.res_key)
|
| 468 |
+
pdbx_pdb_ins_code = residues.apply_array_to_column(
|
| 469 |
+
'insertion_code', atoms.res_key
|
| 470 |
+
)
|
| 471 |
+
string_array.remap(pdbx_pdb_ins_code, mapping={None: '?'}, inplace=True)
|
| 472 |
+
|
| 473 |
+
group_pdb = _residue_name_to_record_name(
|
| 474 |
+
residue_name=label_comp_id, polymer_mask=~non_polymer_atom_mask
|
| 475 |
+
)
|
| 476 |
+
|
| 477 |
+
def tile_for_models(arr: np.ndarray) -> list[str]:
|
| 478 |
+
if atoms.num_models == 1:
|
| 479 |
+
return arr.tolist() # Memory optimisation: np.tile(arr, 1) does a copy.
|
| 480 |
+
return np.tile(arr, atoms.num_models).tolist()
|
| 481 |
+
|
| 482 |
+
raw_mmcif['_atom_site.group_PDB'] = tile_for_models(group_pdb)
|
| 483 |
+
raw_mmcif['_atom_site.label_atom_id'] = tile_for_models(label_atom_id)
|
| 484 |
+
raw_mmcif['_atom_site.type_symbol'] = tile_for_models(type_symbol)
|
| 485 |
+
raw_mmcif['_atom_site.label_comp_id'] = tile_for_models(label_comp_id)
|
| 486 |
+
raw_mmcif['_atom_site.label_asym_id'] = tile_for_models(label_asym_id)
|
| 487 |
+
raw_mmcif['_atom_site.label_entity_id'] = tile_for_models(label_entity_id)
|
| 488 |
+
raw_mmcif['_atom_site.label_seq_id'] = tile_for_models(label_seq_id)
|
| 489 |
+
raw_mmcif['_atom_site.auth_asym_id'] = tile_for_models(auth_asym_id)
|
| 490 |
+
raw_mmcif['_atom_site.auth_seq_id'] = tile_for_models(auth_seq_id)
|
| 491 |
+
raw_mmcif['_atom_site.pdbx_PDB_ins_code'] = tile_for_models(pdbx_pdb_ins_code)
|
| 492 |
+
model_id = np.array(
|
| 493 |
+
[str(i + 1) for i in range(atoms.num_models)], dtype=object
|
| 494 |
+
)
|
| 495 |
+
raw_mmcif['_atom_site.pdbx_PDB_model_num'] = np.repeat(
|
| 496 |
+
model_id, [atoms.size] * atoms.num_models
|
| 497 |
+
).tolist()
|
| 498 |
+
|
| 499 |
+
if bonds.key.size > 0:
|
| 500 |
+
raw_mmcif.update(
|
| 501 |
+
bonds.to_mmcif_dict_from_atom_arrays(
|
| 502 |
+
atom_key=atoms.key,
|
| 503 |
+
chain_id=label_asym_id,
|
| 504 |
+
res_id=label_seq_id,
|
| 505 |
+
res_name=label_comp_id,
|
| 506 |
+
atom_name=label_atom_id,
|
| 507 |
+
auth_asym_id=auth_asym_id,
|
| 508 |
+
auth_seq_id=auth_seq_id,
|
| 509 |
+
insertion_code=np.array(pdbx_pdb_ins_code),
|
| 510 |
+
)
|
| 511 |
+
)
|
| 512 |
+
return raw_mmcif
|
| 513 |
+
|
| 514 |
+
|
| 515 |
+
def _flatten_author_naming_scheme_table(
|
| 516 |
+
res_table: Mapping[str, Mapping[int, str]],
|
| 517 |
+
chain_ids: np.ndarray,
|
| 518 |
+
res_chain_ids: np.ndarray,
|
| 519 |
+
res_ids: np.ndarray,
|
| 520 |
+
default_if_missing: str,
|
| 521 |
+
table_name: str,
|
| 522 |
+
) -> np.ndarray:
|
| 523 |
+
"""Flattens an author naming scheme table consistently with res_ids."""
|
| 524 |
+
if not set(chain_ids).issubset(res_table):
|
| 525 |
+
raise ValueError(
|
| 526 |
+
f'Chain IDs in the chain_id array must be a subset of {table_name} in '
|
| 527 |
+
'author naming scheme:\n'
|
| 528 |
+
f'chain_ids: {sorted(chain_ids)}\n'
|
| 529 |
+
f'{table_name} keys: {sorted(res_table.keys())}'
|
| 530 |
+
)
|
| 531 |
+
|
| 532 |
+
chain_change_mask = res_chain_ids[1:] != res_chain_ids[:-1]
|
| 533 |
+
res_chain_boundaries = np.concatenate(
|
| 534 |
+
([0], np.where(chain_change_mask)[0] + 1, [len(res_chain_ids)])
|
| 535 |
+
)
|
| 536 |
+
|
| 537 |
+
flat_vals = np.empty(len(res_ids), dtype=object)
|
| 538 |
+
for chain_start, chain_end in itertools.pairwise(res_chain_boundaries):
|
| 539 |
+
chain_id = res_chain_ids[chain_start]
|
| 540 |
+
chain_res_ids = res_ids[chain_start:chain_end]
|
| 541 |
+
chain_mapping = res_table[chain_id]
|
| 542 |
+
flat_vals[chain_start:chain_end] = [
|
| 543 |
+
chain_mapping.get(r, default_if_missing) for r in chain_res_ids
|
| 544 |
+
]
|
| 545 |
+
|
| 546 |
+
return flat_vals
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
def tables_from_atom_arrays(
|
| 550 |
+
*,
|
| 551 |
+
res_id: np.ndarray,
|
| 552 |
+
author_naming_scheme: AuthorNamingScheme | None = None,
|
| 553 |
+
all_residues: Mapping[str, Sequence[tuple[str, int]]] | None = None,
|
| 554 |
+
chain_id: np.ndarray | None = None,
|
| 555 |
+
chain_type: np.ndarray | None = None,
|
| 556 |
+
res_name: np.ndarray | None = None,
|
| 557 |
+
atom_key: np.ndarray | None = None,
|
| 558 |
+
atom_name: np.ndarray | None = None,
|
| 559 |
+
atom_element: np.ndarray | None = None,
|
| 560 |
+
atom_x: np.ndarray | None = None,
|
| 561 |
+
atom_y: np.ndarray | None = None,
|
| 562 |
+
atom_z: np.ndarray | None = None,
|
| 563 |
+
atom_b_factor: np.ndarray | None = None,
|
| 564 |
+
atom_occupancy: np.ndarray | None = None,
|
| 565 |
+
) -> tuple[Atoms, Residues, Chains]:
|
| 566 |
+
"""Returns Structure tables constructed from atom array level data.
|
| 567 |
+
|
| 568 |
+
All fields except name and, res_id are optional, all array fields consist of a
|
| 569 |
+
value for each atom in the structure - so residue and chain values should hold
|
| 570 |
+
the same value for each atom in the chain or residue. Fields which are not
|
| 571 |
+
defined are filled with default values.
|
| 572 |
+
|
| 573 |
+
Validation is performed by the Structure constructor where possible - but
|
| 574 |
+
author_naming scheme and all_residues must be checked in this function.
|
| 575 |
+
|
| 576 |
+
It is not possible to construct structures with chains that do not contain
|
| 577 |
+
any resolved residues using this function. If this is necessary, use the
|
| 578 |
+
structure.Structure constructor directly.
|
| 579 |
+
|
| 580 |
+
Args:
|
| 581 |
+
res_id: Integer array of shape [num_atom]. The unique residue identifier for
|
| 582 |
+
each residue. mmCIF field - _atom_site.label_seq_id.
|
| 583 |
+
author_naming_scheme: An optional instance of AuthorNamingScheme to use when
|
| 584 |
+
converting this structure to mmCIF.
|
| 585 |
+
all_residues: An optional mapping from each chain ID (i.e. label_asym_id) to
|
| 586 |
+
a sequence of (label_comp_id, label_seq_id) tuples, one per residue. This
|
| 587 |
+
can contain residues that aren't present in the atom arrays. This is
|
| 588 |
+
common in experimental data where some residues are not resolved but are
|
| 589 |
+
known to be present.
|
| 590 |
+
chain_id: String array of shape [num_atom] of unique chain identifiers.
|
| 591 |
+
mmCIF field - _atom_site.label_asym_id.
|
| 592 |
+
chain_type: String array of shape [num_atom]. The molecular type of the
|
| 593 |
+
current chain (e.g. polyribonucleotide). mmCIF field - _entity_poly.type
|
| 594 |
+
OR _entity.type (for non-polymers).
|
| 595 |
+
res_name: String array of shape [num_atom].. The name of each residue,
|
| 596 |
+
typically a 3 letter string for polypeptides or 1-2 letter strings for
|
| 597 |
+
polynucleotides. mmCIF field - _atom_site.label_comp_id.
|
| 598 |
+
atom_key: A unique sorted integer array, used only by the bonds table to
|
| 599 |
+
identify the atoms participating in each bond. If the bonds table is
|
| 600 |
+
specified then this column must be non-None.
|
| 601 |
+
atom_name: String array of shape [num_atom]. The name of each atom (e.g CA,
|
| 602 |
+
O2', etc.). mmCIF field - _atom_site.label_atom_id.
|
| 603 |
+
atom_element: String array of shape [num_atom]. The element type of each
|
| 604 |
+
atom (e.g. C, O, N, etc.). mmCIF field - _atom_site.type_symbol.
|
| 605 |
+
atom_x: Float array of shape [..., num_atom] of atom x coordinates. May have
|
| 606 |
+
arbitrary leading dimensions, provided that these are consistent across
|
| 607 |
+
all coordinate fields.
|
| 608 |
+
atom_y: Float array of shape [..., num_atom] of atom y coordinates. May have
|
| 609 |
+
arbitrary leading dimensions, provided that these are consistent across
|
| 610 |
+
all coordinate fields.
|
| 611 |
+
atom_z: Float array of shape [..., num_atom] of atom z coordinates. May have
|
| 612 |
+
arbitrary leading dimensions, provided that these are consistent across
|
| 613 |
+
all coordinate fields.
|
| 614 |
+
atom_b_factor: Float array of shape [..., num_atom] or [num_atom] of atom
|
| 615 |
+
b-factors or equivalent. If there are no extra leading dimensions then
|
| 616 |
+
these values are assumed to apply to all coordinates for a given atom. If
|
| 617 |
+
there are leading dimensions then these must match those used by the
|
| 618 |
+
coordinate fields.
|
| 619 |
+
atom_occupancy: Float array of shape [..., num_atom] or [num_atom] of atom
|
| 620 |
+
occupancies or equivalent. If there are no extra leading dimensions then
|
| 621 |
+
these values are assumed to apply to all coordinates for a given atom. If
|
| 622 |
+
there are leading dimensions then these must match those used by the
|
| 623 |
+
coordinate fields.
|
| 624 |
+
"""
|
| 625 |
+
num_atoms = len(res_id)
|
| 626 |
+
|
| 627 |
+
for arr_name, array, dtype in (
|
| 628 |
+
('chain_id', chain_id, object),
|
| 629 |
+
('chain_type', chain_type, object),
|
| 630 |
+
('res_id', res_id, np.int32),
|
| 631 |
+
('res_name', res_name, object),
|
| 632 |
+
('atom_key', atom_key, np.int64),
|
| 633 |
+
('atom_name', atom_name, object),
|
| 634 |
+
('atom_element', atom_element, object),
|
| 635 |
+
):
|
| 636 |
+
if array is not None and array.shape != (num_atoms,):
|
| 637 |
+
raise ValueError(f'{arr_name} shape {array.shape} != ({num_atoms},)')
|
| 638 |
+
if array is not None and array.dtype != dtype:
|
| 639 |
+
raise ValueError(f'{arr_name} dtype {array.dtype} != {dtype}')
|
| 640 |
+
|
| 641 |
+
for arr_name, array in (
|
| 642 |
+
('atom_x', atom_x),
|
| 643 |
+
('atom_y', atom_y),
|
| 644 |
+
('atom_z', atom_z),
|
| 645 |
+
('atom_b_factor', atom_b_factor),
|
| 646 |
+
('atom_occupancy', atom_occupancy),
|
| 647 |
+
):
|
| 648 |
+
if array is not None and array.shape[-1] != num_atoms:
|
| 649 |
+
raise ValueError(f'{arr_name} last dim {array.shape[-1]} != {num_atoms=}')
|
| 650 |
+
if (
|
| 651 |
+
array is not None
|
| 652 |
+
and array.dtype != np.float32
|
| 653 |
+
and array.dtype != np.float64
|
| 654 |
+
):
|
| 655 |
+
raise ValueError(
|
| 656 |
+
f'{arr_name} must be np.float32 or np.float64, got {array.dtype=}'
|
| 657 |
+
)
|
| 658 |
+
|
| 659 |
+
if all_residues is not None and (res_name is None or res_id is None):
|
| 660 |
+
raise ValueError(
|
| 661 |
+
'If all_residues != None, res_name and res_id must not be None either.'
|
| 662 |
+
)
|
| 663 |
+
|
| 664 |
+
if num_atoms == 0:
|
| 665 |
+
return Atoms.make_empty(), Residues.make_empty(), Chains.make_empty()
|
| 666 |
+
|
| 667 |
+
if chain_id is None:
|
| 668 |
+
chain_id = np.full(shape=num_atoms, fill_value='A', dtype=object)
|
| 669 |
+
if res_name is None:
|
| 670 |
+
res_name = np.full(shape=num_atoms, fill_value='UNK', dtype=object)
|
| 671 |
+
|
| 672 |
+
chain_change_mask = chain_id[1:] != chain_id[:-1]
|
| 673 |
+
chain_start = np.concatenate(([0], np.where(chain_change_mask)[0] + 1))
|
| 674 |
+
res_start = np.concatenate(
|
| 675 |
+
([0], np.where((res_id[1:] != res_id[:-1]) | chain_change_mask)[0] + 1)
|
| 676 |
+
)
|
| 677 |
+
|
| 678 |
+
if len(set(chain_id)) != len(chain_start):
|
| 679 |
+
raise ValueError(f'Chain IDs must be contiguous, but got {chain_id}')
|
| 680 |
+
|
| 681 |
+
# We do not support chains with unresolved residues-only in this function.
|
| 682 |
+
chain_ids = chain_id[chain_start]
|
| 683 |
+
if all_residues and set(all_residues.keys()) != set(chain_ids):
|
| 684 |
+
raise ValueError(
|
| 685 |
+
'all_residues must contain the same set of chain IDs as the chain_id '
|
| 686 |
+
f'array:\nall_residues keys: {sorted(all_residues.keys())}\n'
|
| 687 |
+
f'chain_ids: {sorted(chain_ids)}.'
|
| 688 |
+
)
|
| 689 |
+
# Make sure all_residue ordering is consistent with chain_id.
|
| 690 |
+
if all_residues and np.any(list(all_residues.keys()) != chain_ids):
|
| 691 |
+
all_residues = {cid: all_residues[cid] for cid in chain_ids}
|
| 692 |
+
|
| 693 |
+
# Create the chains table.
|
| 694 |
+
num_chains = len(chain_ids)
|
| 695 |
+
chain_keys = np.arange(num_chains, dtype=np.int64)
|
| 696 |
+
chain_key_by_chain_id = dict(zip(chain_ids, chain_keys, strict=True))
|
| 697 |
+
|
| 698 |
+
if chain_type is not None:
|
| 699 |
+
chain_types = chain_type[chain_start]
|
| 700 |
+
else:
|
| 701 |
+
chain_types = np.full(num_chains, mmcif_names.PROTEIN_CHAIN, dtype=object)
|
| 702 |
+
|
| 703 |
+
if author_naming_scheme is not None:
|
| 704 |
+
auth_asym_id = string_array.remap(
|
| 705 |
+
chain_ids, author_naming_scheme.auth_asym_id
|
| 706 |
+
)
|
| 707 |
+
entity_id = string_array.remap(
|
| 708 |
+
chain_ids, author_naming_scheme.entity_id, default_value='.'
|
| 709 |
+
)
|
| 710 |
+
entity_desc = string_array.remap(
|
| 711 |
+
entity_id, author_naming_scheme.entity_desc, default_value='.'
|
| 712 |
+
)
|
| 713 |
+
else:
|
| 714 |
+
auth_asym_id = chain_ids
|
| 715 |
+
entity_id = (chain_keys + 1).astype(str).astype(object)
|
| 716 |
+
entity_desc = np.full(num_chains, '.', dtype=object)
|
| 717 |
+
|
| 718 |
+
chains = Chains(
|
| 719 |
+
key=chain_keys,
|
| 720 |
+
id=chain_ids,
|
| 721 |
+
type=chain_types,
|
| 722 |
+
auth_asym_id=auth_asym_id,
|
| 723 |
+
entity_id=entity_id,
|
| 724 |
+
entity_desc=entity_desc,
|
| 725 |
+
)
|
| 726 |
+
|
| 727 |
+
# Create the residues table.
|
| 728 |
+
if all_residues is not None:
|
| 729 |
+
residue_order = []
|
| 730 |
+
for cid, residues in all_residues.items():
|
| 731 |
+
residue_order.extend((cid, rname, int(rid)) for (rname, rid) in residues)
|
| 732 |
+
res_chain_ids, res_names, res_ids = zip(*residue_order)
|
| 733 |
+
res_chain_ids = np.array(res_chain_ids, dtype=object)
|
| 734 |
+
res_ids = np.array(res_ids, dtype=np.int32)
|
| 735 |
+
res_names = np.array(res_names, dtype=object)
|
| 736 |
+
else:
|
| 737 |
+
res_chain_ids = chain_id[res_start]
|
| 738 |
+
res_ids = res_id[res_start]
|
| 739 |
+
res_names = res_name[res_start]
|
| 740 |
+
residue_order = list(zip(res_chain_ids, res_names, res_ids))
|
| 741 |
+
|
| 742 |
+
if author_naming_scheme is not None and author_naming_scheme.auth_seq_id:
|
| 743 |
+
auth_seq_id = _flatten_author_naming_scheme_table(
|
| 744 |
+
author_naming_scheme.auth_seq_id,
|
| 745 |
+
chain_ids=chain_ids,
|
| 746 |
+
res_chain_ids=res_chain_ids,
|
| 747 |
+
res_ids=res_ids,
|
| 748 |
+
default_if_missing='.',
|
| 749 |
+
table_name='auth_seq_id',
|
| 750 |
+
)
|
| 751 |
+
else:
|
| 752 |
+
auth_seq_id = res_ids.astype(str).astype(object)
|
| 753 |
+
|
| 754 |
+
if author_naming_scheme is not None and author_naming_scheme.insertion_code:
|
| 755 |
+
insertion_code = _flatten_author_naming_scheme_table(
|
| 756 |
+
author_naming_scheme.insertion_code,
|
| 757 |
+
chain_ids=chain_ids,
|
| 758 |
+
res_chain_ids=res_chain_ids,
|
| 759 |
+
res_ids=res_ids,
|
| 760 |
+
default_if_missing='?',
|
| 761 |
+
table_name='insertion_code',
|
| 762 |
+
)
|
| 763 |
+
# Make sure insertion code of None is mapped to '.'.
|
| 764 |
+
insertion_code = string_array.remap(insertion_code, {None: '?'})
|
| 765 |
+
else:
|
| 766 |
+
insertion_code = np.full(shape=len(res_ids), fill_value='?', dtype=object)
|
| 767 |
+
|
| 768 |
+
res_key_by_res = {res: i for i, res in enumerate(residue_order)}
|
| 769 |
+
res_keys = np.arange(len(residue_order), dtype=np.int64)
|
| 770 |
+
res_chain_keys = string_array.remap(
|
| 771 |
+
res_chain_ids, chain_key_by_chain_id
|
| 772 |
+
).astype(np.int64)
|
| 773 |
+
residues = Residues(
|
| 774 |
+
chain_key=res_chain_keys,
|
| 775 |
+
key=res_keys,
|
| 776 |
+
id=res_ids,
|
| 777 |
+
name=res_names,
|
| 778 |
+
auth_seq_id=auth_seq_id,
|
| 779 |
+
insertion_code=insertion_code,
|
| 780 |
+
)
|
| 781 |
+
|
| 782 |
+
if atom_key is None:
|
| 783 |
+
atom_key = np.arange(num_atoms, dtype=np.int64)
|
| 784 |
+
|
| 785 |
+
atom_chain_keys = string_array.remap(chain_id, chain_key_by_chain_id).astype(
|
| 786 |
+
np.int64
|
| 787 |
+
)
|
| 788 |
+
|
| 789 |
+
try:
|
| 790 |
+
atom_res_keys = [res_key_by_res[r] for r in zip(chain_id, res_name, res_id)]
|
| 791 |
+
except KeyError as e:
|
| 792 |
+
missing_chain_id, missing_res_name, missing_res_id = e.args[0]
|
| 793 |
+
raise ValueError(
|
| 794 |
+
'Inconsistent res_name, res_id and all_residues. Could not find '
|
| 795 |
+
f'residue with chain_id={missing_chain_id}, '
|
| 796 |
+
f'res_name={missing_res_name}, res_id={missing_res_id} in all_residues.'
|
| 797 |
+
) from e
|
| 798 |
+
|
| 799 |
+
atoms = Atoms(
|
| 800 |
+
key=atom_key,
|
| 801 |
+
chain_key=atom_chain_keys,
|
| 802 |
+
res_key=np.array(atom_res_keys, dtype=np.int64),
|
| 803 |
+
name=_default(atom_name, ['?'] * num_atoms, object),
|
| 804 |
+
element=_default(atom_element, ['?'] * num_atoms, object),
|
| 805 |
+
x=_default(atom_x, [0.0] * num_atoms, np.float32),
|
| 806 |
+
y=_default(atom_y, [0.0] * num_atoms, np.float32),
|
| 807 |
+
z=_default(atom_z, [0.0] * num_atoms, np.float32),
|
| 808 |
+
b_factor=_default(atom_b_factor, [0.0] * num_atoms, np.float32),
|
| 809 |
+
occupancy=_default(atom_occupancy, [1.0] * num_atoms, np.float32),
|
| 810 |
+
)
|
| 811 |
+
return atoms, residues, chains
|
flax_model/alphafold3/structure/table.py
ADDED
|
@@ -0,0 +1,555 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
"""Table module for atom/residue/chain tables in Structure.
|
| 4 |
+
|
| 5 |
+
Tables are intended to be lightweight collections of columns, loosely based
|
| 6 |
+
on a pandas dataframe, for use in the Structure class.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import abc
|
| 10 |
+
from collections.abc import Callable, Collection, Iterable, Iterator, Mapping, Sequence
|
| 11 |
+
import dataclasses
|
| 12 |
+
import functools
|
| 13 |
+
import graphlib
|
| 14 |
+
import typing
|
| 15 |
+
from typing import Any, Protocol, Self, TypeAlias, TypeVar, overload
|
| 16 |
+
|
| 17 |
+
from flax_model.alphafold3.cpp import string_array
|
| 18 |
+
import numpy as np
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
TableEntry: TypeAlias = str | int | float | None
|
| 22 |
+
FilterPredicate: TypeAlias = (
|
| 23 |
+
TableEntry
|
| 24 |
+
| Iterable[Any] # Workaround for b/326384670. Tighten once fixed.
|
| 25 |
+
| Callable[[Any], bool] # Workaround for b/326384670. Tighten once fixed.
|
| 26 |
+
| Callable[[np.ndarray], bool]
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class RowLookup(Protocol):
|
| 31 |
+
|
| 32 |
+
def get_row_by_key(
|
| 33 |
+
self,
|
| 34 |
+
key: int,
|
| 35 |
+
column_name_map: Mapping[str, str] | None = None,
|
| 36 |
+
) -> Mapping[str, Any]:
|
| 37 |
+
...
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
@dataclasses.dataclass(frozen=True, kw_only=True)
|
| 41 |
+
class Table:
|
| 42 |
+
"""Parent class for structure tables.
|
| 43 |
+
|
| 44 |
+
A table is a collection of columns of equal length, where one column is the
|
| 45 |
+
key. The key uniquely identifies each row in the table.
|
| 46 |
+
|
| 47 |
+
A table can refer to other tables by including a foreign key column, whose
|
| 48 |
+
values are key values from the other table's key column. These column can have
|
| 49 |
+
arbitrary names and are treated like any other integer-valued column.
|
| 50 |
+
|
| 51 |
+
See the `Database` class in this module for utilities for handing sets of
|
| 52 |
+
tables that are related via foreign keys.
|
| 53 |
+
|
| 54 |
+
NB: This does not correspond to an mmCIF table.
|
| 55 |
+
"""
|
| 56 |
+
|
| 57 |
+
key: np.ndarray
|
| 58 |
+
|
| 59 |
+
def __post_init__(self):
|
| 60 |
+
for col_name in self.columns:
|
| 61 |
+
if (col_len := self.get_column(col_name).shape[-1]) != self.size:
|
| 62 |
+
raise ValueError(
|
| 63 |
+
f'All columns should have length {self.size} but got "{col_name}"'
|
| 64 |
+
f' with length {col_len}.'
|
| 65 |
+
)
|
| 66 |
+
self.get_column(col_name).flags.writeable = False # Make col immutable.
|
| 67 |
+
if self.key.size and self.key.min() < 0:
|
| 68 |
+
raise ValueError(
|
| 69 |
+
'Key values must be non-negative. Got negative values:'
|
| 70 |
+
f' {set(self.key[self.key < 0])}'
|
| 71 |
+
)
|
| 72 |
+
self.key.flags.writeable = False # Make key immutable.
|
| 73 |
+
|
| 74 |
+
def __getstate__(self) -> dict[str, Any]:
|
| 75 |
+
"""Returns members with cached properties removed for pickling."""
|
| 76 |
+
cached_props = {
|
| 77 |
+
k
|
| 78 |
+
for k, v in self.__class__.__dict__.items()
|
| 79 |
+
if isinstance(v, functools.cached_property)
|
| 80 |
+
}
|
| 81 |
+
return {k: v for k, v in self.__dict__.items() if k not in cached_props}
|
| 82 |
+
|
| 83 |
+
@functools.cached_property
|
| 84 |
+
def index_by_key(self) -> np.ndarray:
|
| 85 |
+
"""Mapping from key values to their index in the column arrays.
|
| 86 |
+
|
| 87 |
+
i.e.: self.key[index_by_key[k]] == k
|
| 88 |
+
"""
|
| 89 |
+
if not self.key.size:
|
| 90 |
+
return np.array([], dtype=np.int64)
|
| 91 |
+
else:
|
| 92 |
+
index_by_key = np.zeros(np.max(self.key) + 1, dtype=np.int64)
|
| 93 |
+
index_by_key[self.key] = np.arange(self.size)
|
| 94 |
+
return index_by_key
|
| 95 |
+
|
| 96 |
+
@functools.cached_property
|
| 97 |
+
def columns(self) -> tuple[str, ...]:
|
| 98 |
+
"""The names of the columns in the table, including the key column."""
|
| 99 |
+
return tuple(field.name for field in dataclasses.fields(self))
|
| 100 |
+
|
| 101 |
+
@functools.cached_property
|
| 102 |
+
def items(self) -> Mapping[str, np.ndarray]:
|
| 103 |
+
"""Returns the mapping from column names to column values."""
|
| 104 |
+
return {col: getattr(self, col) for col in self.columns}
|
| 105 |
+
|
| 106 |
+
@functools.cached_property
|
| 107 |
+
def size(self) -> int:
|
| 108 |
+
"""The number of rows in the table."""
|
| 109 |
+
return self.key.shape[-1]
|
| 110 |
+
|
| 111 |
+
def __len__(self) -> int:
|
| 112 |
+
return self.size
|
| 113 |
+
|
| 114 |
+
def get_column(self, column_name: str) -> np.ndarray:
|
| 115 |
+
"""Gets a column by name."""
|
| 116 |
+
# Performance optimisation: use the cached columns, instead of getattr.
|
| 117 |
+
return self.items[column_name]
|
| 118 |
+
|
| 119 |
+
def apply_array(self, arr: np.ndarray) -> Self:
|
| 120 |
+
"""Returns a sliced table using a key (!= index) array or a boolean mask."""
|
| 121 |
+
if arr.dtype == bool and np.all(arr):
|
| 122 |
+
return self # Shortcut: No-op, so just return.
|
| 123 |
+
|
| 124 |
+
return self.copy_and_update(**{
|
| 125 |
+
column_name: self.apply_array_to_column(column_name, arr)
|
| 126 |
+
for column_name in self.columns
|
| 127 |
+
})
|
| 128 |
+
|
| 129 |
+
def apply_index(self, index_arr: np.ndarray) -> Self:
|
| 130 |
+
"""Returns a sliced table using an index (!= key) array."""
|
| 131 |
+
if index_arr.dtype == bool:
|
| 132 |
+
raise ValueError('The index array must not be a boolean mask.')
|
| 133 |
+
|
| 134 |
+
return self.copy_and_update(
|
| 135 |
+
**{col: self.get_column(col)[..., index_arr] for col in self.columns}
|
| 136 |
+
)
|
| 137 |
+
|
| 138 |
+
def apply_array_to_column(
|
| 139 |
+
self,
|
| 140 |
+
column_name: str,
|
| 141 |
+
arr: np.ndarray,
|
| 142 |
+
) -> np.ndarray:
|
| 143 |
+
"""Returns a sliced column array using a key array or a boolean mask."""
|
| 144 |
+
if arr.dtype == bool:
|
| 145 |
+
return self.get_column(column_name)[..., arr]
|
| 146 |
+
else:
|
| 147 |
+
return self.get_column(column_name)[..., self.index_by_key[arr]]
|
| 148 |
+
|
| 149 |
+
def get_value_by_index(self, column_name: str, index: int) -> Any:
|
| 150 |
+
return self.get_column(column_name)[index]
|
| 151 |
+
|
| 152 |
+
def get_value_by_key(
|
| 153 |
+
self,
|
| 154 |
+
column_name: str,
|
| 155 |
+
key: int | np.integer,
|
| 156 |
+
) -> TableEntry:
|
| 157 |
+
"""Gets the value of a column at the row with specified key value."""
|
| 158 |
+
return self.get_value_by_index(column_name, self.index_by_key[key])
|
| 159 |
+
|
| 160 |
+
@overload
|
| 161 |
+
def __getitem__(self, key: str) -> np.ndarray:
|
| 162 |
+
...
|
| 163 |
+
|
| 164 |
+
@overload
|
| 165 |
+
def __getitem__(self, key: np.ndarray) -> 'Table':
|
| 166 |
+
...
|
| 167 |
+
|
| 168 |
+
@overload
|
| 169 |
+
def __getitem__(self, key: tuple[str, int | np.integer]) -> TableEntry:
|
| 170 |
+
...
|
| 171 |
+
|
| 172 |
+
@overload
|
| 173 |
+
def __getitem__(self, key: tuple[str, np.ndarray]) -> np.ndarray:
|
| 174 |
+
...
|
| 175 |
+
|
| 176 |
+
def __getitem__(self, key):
|
| 177 |
+
match key:
|
| 178 |
+
case str():
|
| 179 |
+
return self.get_column(key)
|
| 180 |
+
case np.ndarray() as key_arr_or_mask:
|
| 181 |
+
return self.apply_array(key_arr_or_mask)
|
| 182 |
+
case str() as col, int() | np.integer() as key_val:
|
| 183 |
+
return self.get_value_by_key(col, key_val)
|
| 184 |
+
case str() as col, np.ndarray() as key_arr_or_mask:
|
| 185 |
+
return self.apply_array_to_column(col, key_arr_or_mask)
|
| 186 |
+
case _:
|
| 187 |
+
if isinstance(key, tuple):
|
| 188 |
+
err_msg = f'{key}, type: tuple({[type(v) for v in key]})'
|
| 189 |
+
else:
|
| 190 |
+
err_msg = f'{key}, type: {type(key)}'
|
| 191 |
+
raise KeyError(err_msg)
|
| 192 |
+
|
| 193 |
+
def get_row_by_key(
|
| 194 |
+
self,
|
| 195 |
+
key: int,
|
| 196 |
+
column_name_map: Mapping[str, str] | None = None,
|
| 197 |
+
) -> dict[str, Any]:
|
| 198 |
+
"""Gets the row with specified key value."""
|
| 199 |
+
return self.get_row_by_index(
|
| 200 |
+
self.index_by_key[key], column_name_map=column_name_map
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
def get_row_by_index(
|
| 204 |
+
self,
|
| 205 |
+
index: int,
|
| 206 |
+
column_name_map: Mapping[str, str] | None = None,
|
| 207 |
+
) -> dict[str, Any]:
|
| 208 |
+
"""Gets the row at the specified index."""
|
| 209 |
+
if column_name_map is not None:
|
| 210 |
+
return {
|
| 211 |
+
renamed_col: self.get_value_by_index(col, index)
|
| 212 |
+
for renamed_col, col in column_name_map.items()
|
| 213 |
+
}
|
| 214 |
+
else:
|
| 215 |
+
return {col: self.get_value_by_index(col, index) for col in self.columns}
|
| 216 |
+
|
| 217 |
+
def iterrows(
|
| 218 |
+
self,
|
| 219 |
+
*,
|
| 220 |
+
row_keys: np.ndarray | None = None,
|
| 221 |
+
column_name_map: Mapping[str, str] | None = None,
|
| 222 |
+
**table_by_foreign_key_col: RowLookup,
|
| 223 |
+
) -> Iterator[Mapping[str, Any]]:
|
| 224 |
+
"""Yields rows from the table.
|
| 225 |
+
|
| 226 |
+
This can be used to easily convert a table to a Pandas dataframe:
|
| 227 |
+
|
| 228 |
+
```py
|
| 229 |
+
df = pd.DataFrame(table.iterrows())
|
| 230 |
+
```
|
| 231 |
+
|
| 232 |
+
Args:
|
| 233 |
+
row_keys: An optional array of keys of rows to yield. If None, all rows
|
| 234 |
+
will be yielded.
|
| 235 |
+
column_name_map: An optional mapping from desired keys in the row dicts to
|
| 236 |
+
the names of the columns they correspond to.
|
| 237 |
+
**table_by_foreign_key_col: An optional mapping from column names in this
|
| 238 |
+
table, which are expected to be columns of foreign keys, to the table
|
| 239 |
+
that the foreign keys point into. If provided, then the yielded rows
|
| 240 |
+
will include data from the foreign tables at the appropriate key.
|
| 241 |
+
"""
|
| 242 |
+
if row_keys is not None:
|
| 243 |
+
row_indices = self.index_by_key[row_keys]
|
| 244 |
+
else:
|
| 245 |
+
row_indices = range(self.size)
|
| 246 |
+
for i in row_indices:
|
| 247 |
+
row = self.get_row_by_index(i, column_name_map=column_name_map)
|
| 248 |
+
for key_col, table in table_by_foreign_key_col.items():
|
| 249 |
+
foreign_key = self[key_col][i]
|
| 250 |
+
foreign_row = table.get_row_by_key(foreign_key)
|
| 251 |
+
row.update(foreign_row)
|
| 252 |
+
yield row
|
| 253 |
+
|
| 254 |
+
def with_column_names(
|
| 255 |
+
self, column_name_map: Mapping[str, str]
|
| 256 |
+
) -> 'RenamedTableView':
|
| 257 |
+
"""Returns a view of this table with mapped column names."""
|
| 258 |
+
return RenamedTableView(self, column_name_map=column_name_map)
|
| 259 |
+
|
| 260 |
+
def make_filter_mask(
|
| 261 |
+
self,
|
| 262 |
+
mask: np.ndarray | None = None,
|
| 263 |
+
*,
|
| 264 |
+
apply_per_element: bool = False,
|
| 265 |
+
**predicate_by_col: FilterPredicate,
|
| 266 |
+
) -> np.ndarray | None:
|
| 267 |
+
"""Returns a boolean array of rows to keep, or None if all can be kept.
|
| 268 |
+
|
| 269 |
+
Args:
|
| 270 |
+
mask: See `Table.filter`.
|
| 271 |
+
apply_per_element: See `Table.filter`.
|
| 272 |
+
**predicate_by_col: See `Table.filter`.
|
| 273 |
+
|
| 274 |
+
Returns:
|
| 275 |
+
Either a boolean NumPy array of length `(self.size,)` denoting which rows
|
| 276 |
+
should be kept according to the input mask and predicates, or None. None
|
| 277 |
+
implies there is no filtering required, and is used where possible
|
| 278 |
+
instead of an all-True array to save time and space.
|
| 279 |
+
"""
|
| 280 |
+
if mask is None:
|
| 281 |
+
if not predicate_by_col:
|
| 282 |
+
return None
|
| 283 |
+
else:
|
| 284 |
+
mask = np.ones((self.size,), dtype=bool)
|
| 285 |
+
else:
|
| 286 |
+
if mask.shape != (self.size,):
|
| 287 |
+
raise ValueError(
|
| 288 |
+
f'mask must have shape ({self.size},). Got: {mask.shape}.'
|
| 289 |
+
)
|
| 290 |
+
if mask.dtype != bool:
|
| 291 |
+
raise ValueError(f'mask must have dtype bool. Got: {mask.dtype}.')
|
| 292 |
+
|
| 293 |
+
for col, predicate in predicate_by_col.items():
|
| 294 |
+
if self[col].ndim > 1:
|
| 295 |
+
raise ValueError(
|
| 296 |
+
f'Cannot filter by column {col} with more than 1 dimension.'
|
| 297 |
+
)
|
| 298 |
+
|
| 299 |
+
callable_predicates = []
|
| 300 |
+
if not callable(predicate):
|
| 301 |
+
if isinstance(predicate, Iterable) and not isinstance(predicate, str):
|
| 302 |
+
target_vals = predicate
|
| 303 |
+
else:
|
| 304 |
+
target_vals = [predicate]
|
| 305 |
+
for target_val in target_vals:
|
| 306 |
+
callable_predicates.append(lambda x, target=target_val: x == target)
|
| 307 |
+
else:
|
| 308 |
+
callable_predicates.append(predicate)
|
| 309 |
+
|
| 310 |
+
field_mask = np.zeros_like(mask)
|
| 311 |
+
for callable_predicate in callable_predicates:
|
| 312 |
+
if not apply_per_element:
|
| 313 |
+
callable_predicate = typing.cast(
|
| 314 |
+
Callable[[np.ndarray], bool], callable_predicate
|
| 315 |
+
)
|
| 316 |
+
predicate_result = callable_predicate(self.get_column(col))
|
| 317 |
+
else:
|
| 318 |
+
predicate_result = np.array(
|
| 319 |
+
[callable_predicate(elem) for elem in self.get_column(col)]
|
| 320 |
+
)
|
| 321 |
+
np.logical_or(field_mask, predicate_result, out=field_mask)
|
| 322 |
+
np.logical_and(mask, field_mask, out=mask) # Update in-place.
|
| 323 |
+
return mask
|
| 324 |
+
|
| 325 |
+
def filter(
|
| 326 |
+
self,
|
| 327 |
+
mask: np.ndarray | None = None,
|
| 328 |
+
*,
|
| 329 |
+
apply_per_element: bool = False,
|
| 330 |
+
invert: bool = False,
|
| 331 |
+
**predicate_by_col: FilterPredicate,
|
| 332 |
+
) -> Self:
|
| 333 |
+
"""Filters the table using mask and/or predicates and returns a new table.
|
| 334 |
+
|
| 335 |
+
Predicates can be either:
|
| 336 |
+
1. A constant value, e.g. `'CA'`. In this case then only rows that match
|
| 337 |
+
this value for the given column are retained.
|
| 338 |
+
2. A (non-string) iterable e.g. `('A', 'B')`. In this
|
| 339 |
+
case then rows are retained if they match any of the provided values for
|
| 340 |
+
the given column.
|
| 341 |
+
3. A boolean function e.g. `lambda b_fac: b_fac < 100.0`.
|
| 342 |
+
In this case then only rows that evaluate to `True` are retained. By
|
| 343 |
+
default this function's parameter is expected to be an array, unless
|
| 344 |
+
`apply_per_element=True`.
|
| 345 |
+
|
| 346 |
+
Args:
|
| 347 |
+
mask: An optional boolean NumPy array with length equal to the table size.
|
| 348 |
+
If provided then this will be combined with the other predicates so that
|
| 349 |
+
a row is included if it is masked-in *and* matches all the predicates.
|
| 350 |
+
apply_per_element: Whether apply predicates to each element in the column
|
| 351 |
+
individually, or to pass the whole column array to the predicate.
|
| 352 |
+
invert: If True then the returned table will contain exactly those rows
|
| 353 |
+
that would be removed if this was `False`.
|
| 354 |
+
**predicate_by_col: A mapping from column name to a predicate. Filtered
|
| 355 |
+
columns must be 1D arrays. If multiple columns are provided as keyword
|
| 356 |
+
arguments then each predicate is applied and the results are combined
|
| 357 |
+
using a boolean AND operation, so an atom is only retained if it passes
|
| 358 |
+
all predicates.
|
| 359 |
+
|
| 360 |
+
Returns:
|
| 361 |
+
A new table with the desired rows retained (or filtered out if
|
| 362 |
+
`invert=True`).
|
| 363 |
+
|
| 364 |
+
Raises:
|
| 365 |
+
ValueError: If mask is provided and is not a bool array with shape
|
| 366 |
+
`(num_atoms,)`.
|
| 367 |
+
"""
|
| 368 |
+
filter_mask = self.make_filter_mask(
|
| 369 |
+
mask, apply_per_element=apply_per_element, **predicate_by_col
|
| 370 |
+
)
|
| 371 |
+
if filter_mask is None:
|
| 372 |
+
# No mask or predicate was specified, so we can return early.
|
| 373 |
+
if not invert:
|
| 374 |
+
return self
|
| 375 |
+
else:
|
| 376 |
+
return self[np.array((), dtype=np.int64)]
|
| 377 |
+
else:
|
| 378 |
+
return self[~filter_mask if invert else filter_mask]
|
| 379 |
+
|
| 380 |
+
def _validate_keys_are_column_names(self, keys: Collection[str]) -> None:
|
| 381 |
+
"""Raises an error if any of the keys are not column names."""
|
| 382 |
+
if mismatches := set(keys) - set(self.columns):
|
| 383 |
+
raise ValueError(f'Invalid column names: {sorted(mismatches)}.')
|
| 384 |
+
|
| 385 |
+
def copy_and_update(self, **new_column_by_column_name: np.ndarray) -> Self:
|
| 386 |
+
"""Returns a copy of this table with the specified changes applied.
|
| 387 |
+
|
| 388 |
+
Args:
|
| 389 |
+
**new_column_by_column_name: New values for the specified columns.
|
| 390 |
+
|
| 391 |
+
Raises:
|
| 392 |
+
ValueError: If a specified column name is not a column in this table.
|
| 393 |
+
"""
|
| 394 |
+
self._validate_keys_are_column_names(new_column_by_column_name)
|
| 395 |
+
return dataclasses.replace(self, **new_column_by_column_name)
|
| 396 |
+
|
| 397 |
+
def copy_and_remap(
|
| 398 |
+
self, **mapping_by_col: Mapping[TableEntry, TableEntry]
|
| 399 |
+
) -> Self:
|
| 400 |
+
"""Returns a copy of the table with the specified columns remapped.
|
| 401 |
+
|
| 402 |
+
Args:
|
| 403 |
+
**mapping_by_col: Each kwarg key should be the name of one of this table's
|
| 404 |
+
columns, and each value should be a mapping. The values in the column
|
| 405 |
+
will be looked up in the mapping and replaced with the result if one is
|
| 406 |
+
found.
|
| 407 |
+
|
| 408 |
+
Raises:
|
| 409 |
+
ValueError: If a specified column name is not a column in this table.
|
| 410 |
+
"""
|
| 411 |
+
self._validate_keys_are_column_names(mapping_by_col)
|
| 412 |
+
if not self.size:
|
| 413 |
+
return self
|
| 414 |
+
remapped_cols = {}
|
| 415 |
+
for column_name, mapping in mapping_by_col.items():
|
| 416 |
+
col_arr = self.get_column(column_name)
|
| 417 |
+
if col_arr.dtype == object:
|
| 418 |
+
remapped = string_array.remap(col_arr, mapping)
|
| 419 |
+
else:
|
| 420 |
+
remapped = np.vectorize(lambda x: mapping.get(x, x))(col_arr) # pylint: disable=cell-var-from-loop
|
| 421 |
+
remapped_cols[column_name] = remapped
|
| 422 |
+
return self.copy_and_update(**remapped_cols)
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
class RenamedTableView:
|
| 426 |
+
"""View of a table with renamed column names."""
|
| 427 |
+
|
| 428 |
+
def __init__(self, table: Table, column_name_map: Mapping[str, str]):
|
| 429 |
+
self._table = table
|
| 430 |
+
self._column_name_map = column_name_map
|
| 431 |
+
|
| 432 |
+
def get_row_by_key(
|
| 433 |
+
self,
|
| 434 |
+
key: int,
|
| 435 |
+
column_name_map: Mapping[str, str] | None = None,
|
| 436 |
+
) -> Mapping[str, Any]:
|
| 437 |
+
del column_name_map
|
| 438 |
+
return self._table.get_row_by_key(
|
| 439 |
+
key, column_name_map=self._column_name_map
|
| 440 |
+
)
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
_DatabaseT = TypeVar('_DatabaseT', bound='Database')
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
class Database(abc.ABC):
|
| 447 |
+
"""Relational database base class."""
|
| 448 |
+
|
| 449 |
+
@property
|
| 450 |
+
@abc.abstractmethod
|
| 451 |
+
def tables(self) -> Collection[str]:
|
| 452 |
+
"""The names of the tables in this database."""
|
| 453 |
+
|
| 454 |
+
@abc.abstractmethod
|
| 455 |
+
def get_table(self, table_name: str) -> Table:
|
| 456 |
+
"""Gets the table with the given name."""
|
| 457 |
+
|
| 458 |
+
@property
|
| 459 |
+
@abc.abstractmethod
|
| 460 |
+
def foreign_keys(self) -> Mapping[str, Collection[tuple[str, str]]]:
|
| 461 |
+
"""Describes the relationship between keys in the database.
|
| 462 |
+
|
| 463 |
+
Returns:
|
| 464 |
+
A map from table names to pairs of `(column_name, foreign_table_name)`
|
| 465 |
+
where `column_name` is a column containing foreign keys in the table named
|
| 466 |
+
by the key, and the `foreign_table_name` is the name of the table that
|
| 467 |
+
those foreign keys refer to.
|
| 468 |
+
"""
|
| 469 |
+
|
| 470 |
+
@abc.abstractmethod
|
| 471 |
+
def copy_and_update(
|
| 472 |
+
self: _DatabaseT,
|
| 473 |
+
**new_field_by_field_name: ...,
|
| 474 |
+
) -> _DatabaseT:
|
| 475 |
+
"""Returns a copy of this database with the specified changes applied."""
|
| 476 |
+
|
| 477 |
+
|
| 478 |
+
def table_dependency_order(db: Database) -> Iterable[str]:
|
| 479 |
+
"""Yields the names of the tables in the database in dependency order.
|
| 480 |
+
|
| 481 |
+
This order guarantees that a table appears after all other tables that
|
| 482 |
+
it refers to using foreign keys. Specifically A < B implies that A contains
|
| 483 |
+
no column that refers to B.key as a foreign key.
|
| 484 |
+
|
| 485 |
+
Args:
|
| 486 |
+
db: The database that defines the table names and foreign keys.
|
| 487 |
+
"""
|
| 488 |
+
connections: dict[str, set[str]] = {}
|
| 489 |
+
for table_name in db.tables:
|
| 490 |
+
connection_set = set()
|
| 491 |
+
for _, foreign_table in db.foreign_keys.get(table_name, ()):
|
| 492 |
+
connection_set.add(foreign_table)
|
| 493 |
+
connections[table_name] = connection_set
|
| 494 |
+
yield from graphlib.TopologicalSorter(connections).static_order()
|
| 495 |
+
|
| 496 |
+
|
| 497 |
+
def concat_databases(dbs: Sequence[_DatabaseT]) -> _DatabaseT:
|
| 498 |
+
"""Concatenates the tables across a sequence of databases.
|
| 499 |
+
|
| 500 |
+
Args:
|
| 501 |
+
dbs: A non-empty sequence of database instances of the same type.
|
| 502 |
+
|
| 503 |
+
Returns:
|
| 504 |
+
A new database containing the concatenated tables from the input databases.
|
| 505 |
+
|
| 506 |
+
Raises:
|
| 507 |
+
ValueError: If `dbs` is empty or `dbs` contains different Database
|
| 508 |
+
types.
|
| 509 |
+
"""
|
| 510 |
+
if not dbs:
|
| 511 |
+
raise ValueError('Need at least one value to concatenate.')
|
| 512 |
+
distinct_db_types = {type(db) for db in dbs}
|
| 513 |
+
if len(distinct_db_types) > 1:
|
| 514 |
+
raise ValueError(
|
| 515 |
+
f'All `dbs` must be of the same type, got: {distinct_db_types}'
|
| 516 |
+
)
|
| 517 |
+
|
| 518 |
+
first_db, *other_dbs = dbs
|
| 519 |
+
concatted_tables: dict[str, Table] = {}
|
| 520 |
+
key_offsets: dict[str, list[int]] = {}
|
| 521 |
+
for table_name in table_dependency_order(first_db):
|
| 522 |
+
first_table = first_db.get_table(table_name)
|
| 523 |
+
columns: dict[str, list[np.ndarray]] = {
|
| 524 |
+
column_name: [first_table.get_column(column_name)]
|
| 525 |
+
for column_name in first_table.columns
|
| 526 |
+
}
|
| 527 |
+
key_offsets[table_name] = [
|
| 528 |
+
first_table.key.max() + 1 if first_table.size else 0
|
| 529 |
+
]
|
| 530 |
+
|
| 531 |
+
for prev_index, db in enumerate(other_dbs):
|
| 532 |
+
table = db.get_table(table_name)
|
| 533 |
+
for col_name in table.columns:
|
| 534 |
+
columns[col_name].append(table.get_column(col_name))
|
| 535 |
+
key_offset = key_offsets[table_name][prev_index]
|
| 536 |
+
offset_key = table.key + key_offset
|
| 537 |
+
columns['key'][-1] = offset_key
|
| 538 |
+
if table.size:
|
| 539 |
+
key_offsets[table_name].append(offset_key.max() + 1)
|
| 540 |
+
else:
|
| 541 |
+
key_offsets[table_name].append(key_offsets[table_name][prev_index])
|
| 542 |
+
for fkey_col_name, foreign_table_name in first_db.foreign_keys.get(
|
| 543 |
+
table_name, []
|
| 544 |
+
):
|
| 545 |
+
fkey_columns = columns[fkey_col_name]
|
| 546 |
+
fkey_columns[-1] = (
|
| 547 |
+
fkey_columns[-1] + key_offsets[foreign_table_name][prev_index]
|
| 548 |
+
)
|
| 549 |
+
|
| 550 |
+
concatted_columns = {
|
| 551 |
+
column_name: np.concatenate(values, axis=-1)
|
| 552 |
+
for column_name, values in columns.items()
|
| 553 |
+
}
|
| 554 |
+
concatted_tables[table_name] = (type(first_table))(**concatted_columns)
|
| 555 |
+
return first_db.copy_and_update(**concatted_tables)
|
flax_model/alphafold3/structure/test_utils.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
|
| 3 |
+
"""Utilities for structure module testing."""
|
| 4 |
+
|
| 5 |
+
import dataclasses
|
| 6 |
+
|
| 7 |
+
from absl.testing import parameterized
|
| 8 |
+
from flax_model.alphafold3 import structure
|
| 9 |
+
from flax_model.alphafold3.common.testing import data
|
| 10 |
+
import numpy as np
|
| 11 |
+
import tree
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class StructureTestCase(parameterized.TestCase):
|
| 15 |
+
"""Testing utilities for working with structure.Structure."""
|
| 16 |
+
|
| 17 |
+
def assertAuthorNamingSchemeEqual(self, ans1, ans2): # pylint: disable=invalid-name
|
| 18 |
+
"""Walks naming scheme, making sure all elements are equal."""
|
| 19 |
+
if ans1 is None or ans2 is None:
|
| 20 |
+
self.assertIsNone(ans1)
|
| 21 |
+
self.assertIsNone(ans2)
|
| 22 |
+
return
|
| 23 |
+
flat_ans1 = dict(tree.flatten_with_path(dataclasses.asdict(ans1)))
|
| 24 |
+
flat_ans2 = dict(tree.flatten_with_path(dataclasses.asdict(ans2)))
|
| 25 |
+
for k, v in flat_ans1.items():
|
| 26 |
+
self.assertEqual(v, flat_ans2[k], msg=str(k))
|
| 27 |
+
for k, v in flat_ans2.items():
|
| 28 |
+
self.assertEqual(v, flat_ans1[k], msg=str(k))
|
| 29 |
+
|
| 30 |
+
def assertAllResiduesEqual(self, all_res1, all_res2): # pylint: disable=invalid-name
|
| 31 |
+
"""Walks all residues, making sure alll elements are equal."""
|
| 32 |
+
if all_res1 is None or all_res2 is None:
|
| 33 |
+
self.assertIsNone(all_res1)
|
| 34 |
+
self.assertIsNone(all_res2)
|
| 35 |
+
return
|
| 36 |
+
self.assertSameElements(all_res1.keys(), all_res2.keys())
|
| 37 |
+
for chain_id, chain_res in all_res1.items():
|
| 38 |
+
self.assertSequenceEqual(chain_res, all_res2[chain_id], msg=chain_id)
|
| 39 |
+
|
| 40 |
+
def assertBioassemblyDataEqual(self, data1, data2): # pylint: disable=invalid-name
|
| 41 |
+
if data1 is None or data2 is None:
|
| 42 |
+
self.assertIsNone(data1)
|
| 43 |
+
self.assertIsNone(data2)
|
| 44 |
+
return
|
| 45 |
+
self.assertDictEqual(data1.to_mmcif_dict(), data2.to_mmcif_dict())
|
| 46 |
+
|
| 47 |
+
def assertChemicalComponentsDataEqual( # pylint: disable=invalid-name
|
| 48 |
+
self,
|
| 49 |
+
data1,
|
| 50 |
+
data2,
|
| 51 |
+
allow_chem_comp_data_extension,
|
| 52 |
+
):
|
| 53 |
+
"""Checks whether two ChemicalComponentData objects are considered equal."""
|
| 54 |
+
if data1 is None or data2 is None:
|
| 55 |
+
self.assertIsNone(data1)
|
| 56 |
+
self.assertIsNone(data2)
|
| 57 |
+
return
|
| 58 |
+
if (not allow_chem_comp_data_extension) or (
|
| 59 |
+
data1.chem_comp.keys() ^ data2.chem_comp.keys()
|
| 60 |
+
):
|
| 61 |
+
self.assertDictEqual(data1.chem_comp, data2.chem_comp)
|
| 62 |
+
else:
|
| 63 |
+
mismatching_values = []
|
| 64 |
+
for component_id in data1.chem_comp:
|
| 65 |
+
found = data1.chem_comp[component_id]
|
| 66 |
+
expected = data2.chem_comp[component_id]
|
| 67 |
+
if not found.extends(expected):
|
| 68 |
+
mismatching_values.append((component_id, expected, found))
|
| 69 |
+
|
| 70 |
+
if mismatching_values:
|
| 71 |
+
mismatch_err_msgs = '\n'.join(
|
| 72 |
+
f'{component_id}: {expected} or its extension expected,'
|
| 73 |
+
f' but {found} found.'
|
| 74 |
+
for component_id, expected, found in mismatching_values
|
| 75 |
+
)
|
| 76 |
+
self.fail(
|
| 77 |
+
f'Mismatching values for `_chem_comp` table: {mismatch_err_msgs}',
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
def assertBondsEqual(self, bonds1, bonds2, atom_key1, atom_key2): # pylint: disable=invalid-name
|
| 81 |
+
"""Checks whether two Bonds objects are considered equal."""
|
| 82 |
+
# An empty bonds table is functionally equivalent to an empty bonds table.
|
| 83 |
+
# NB: this can only ever be None in structure v1.
|
| 84 |
+
if bonds1 is None or not bonds1.size or bonds2 is None or not bonds2.size:
|
| 85 |
+
self.assertTrue(bonds1 is None or not bonds1.size, msg=f'{bonds1=}')
|
| 86 |
+
self.assertTrue(bonds2 is None or not bonds2.size, msg=f'{bonds2=}')
|
| 87 |
+
return
|
| 88 |
+
|
| 89 |
+
ptnr1_indices1, ptnr2_indices1 = bonds1.get_atom_indices(atom_key1)
|
| 90 |
+
ptnr1_indices2, ptnr2_indices2 = bonds2.get_atom_indices(atom_key2)
|
| 91 |
+
np.testing.assert_array_equal(ptnr1_indices1, ptnr1_indices2)
|
| 92 |
+
np.testing.assert_array_equal(ptnr2_indices1, ptnr2_indices2)
|
| 93 |
+
np.testing.assert_array_equal(bonds1.type, bonds2.type)
|
| 94 |
+
np.testing.assert_array_equal(bonds1.role, bonds2.role)
|
| 95 |
+
|
| 96 |
+
def assertStructuresEqual( # pylint: disable=invalid-name
|
| 97 |
+
self,
|
| 98 |
+
struc1,
|
| 99 |
+
struc2,
|
| 100 |
+
*,
|
| 101 |
+
ignore_fields=None,
|
| 102 |
+
allow_chem_comp_data_extension=False,
|
| 103 |
+
atol=0,
|
| 104 |
+
):
|
| 105 |
+
"""Checks whether two Structure objects could be considered equal.
|
| 106 |
+
|
| 107 |
+
Args:
|
| 108 |
+
struc1: First Structure object.
|
| 109 |
+
struc2: Second Structure object.
|
| 110 |
+
ignore_fields: Fields not taken into account during comparison.
|
| 111 |
+
allow_chem_comp_data_extension: Whether to allow data of `_chem_comp`
|
| 112 |
+
table to differ if `struc2` is missing some fields, but `struc1` has
|
| 113 |
+
specific values for them.
|
| 114 |
+
atol: Absolute tolerance for floating point comparisons (in
|
| 115 |
+
np.testing.assert_allclose).
|
| 116 |
+
"""
|
| 117 |
+
for field in sorted(structure.GLOBAL_FIELDS):
|
| 118 |
+
if ignore_fields and field in ignore_fields:
|
| 119 |
+
continue
|
| 120 |
+
if field == 'author_naming_scheme':
|
| 121 |
+
self.assertAuthorNamingSchemeEqual(struc1[field], struc2[field])
|
| 122 |
+
elif field == 'all_residues':
|
| 123 |
+
self.assertAllResiduesEqual(struc1[field], struc2[field])
|
| 124 |
+
elif field == 'bioassembly_data':
|
| 125 |
+
self.assertBioassemblyDataEqual(struc1[field], struc2[field])
|
| 126 |
+
elif field == 'chemical_components_data':
|
| 127 |
+
self.assertChemicalComponentsDataEqual(
|
| 128 |
+
struc1[field], struc2[field], allow_chem_comp_data_extension
|
| 129 |
+
)
|
| 130 |
+
elif field == 'bonds':
|
| 131 |
+
self.assertBondsEqual(
|
| 132 |
+
struc1.bonds, struc2.bonds, struc1.atom_key, struc2.atom_key
|
| 133 |
+
)
|
| 134 |
+
else:
|
| 135 |
+
self.assertEqual(struc1[field], struc2[field], msg=field)
|
| 136 |
+
|
| 137 |
+
# The chain order within a structure is arbitrary so in order to
|
| 138 |
+
# directly compare arrays we first align struc1 to struc2 and check that
|
| 139 |
+
# the number of atoms doesn't change.
|
| 140 |
+
num_atoms = struc1.num_atoms
|
| 141 |
+
self.assertEqual(struc2.num_atoms, num_atoms)
|
| 142 |
+
struc1 = struc1.order_and_drop_atoms_to_match(struc2)
|
| 143 |
+
self.assertEqual(struc1.num_atoms, num_atoms)
|
| 144 |
+
|
| 145 |
+
for field in sorted(structure.ARRAY_FIELDS):
|
| 146 |
+
if field == 'atom_key':
|
| 147 |
+
# atom_key has no external meaning, so it doesn't matter whether it
|
| 148 |
+
# differs between two structures.
|
| 149 |
+
continue
|
| 150 |
+
if ignore_fields and field in ignore_fields:
|
| 151 |
+
continue
|
| 152 |
+
self.assertEqual(struc1[field] is None, struc2[field] is None, msg=field)
|
| 153 |
+
|
| 154 |
+
if np.issubdtype(struc1[field].dtype, np.inexact):
|
| 155 |
+
np.testing.assert_allclose(
|
| 156 |
+
struc1[field], struc2[field], err_msg=field, atol=atol
|
| 157 |
+
)
|
| 158 |
+
else:
|
| 159 |
+
np.testing.assert_array_equal(
|
| 160 |
+
struc1[field], struc2[field], err_msg=field
|
| 161 |
+
)
|
flax_model/alphafold3/test_data/__init__.py
ADDED
|
File without changes
|
flax_model/alphafold3/test_data/featurised_example.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"aatype": "46551530df4e79371352989100ae6af82ccd939009517b788173bdbb323ae40a",
|
| 4 |
+
"asym_id": "42c714885d17f6c0fcfebebd171b5ed7d7e77a56cf9c4983d9ff9ff90995bd1c",
|
| 5 |
+
"cleaned_struc": "<<structure>>",
|
| 6 |
+
"deletion_matrix": "54f980b5b3be8ce80cb6490c527e38d681deade50f239f2cb7d23cf9d0108c37",
|
| 7 |
+
"deletion_mean": "655a3ef0465a9f30fddf25f4dde0c19a05c6f9069b83961800c1944165955273",
|
| 8 |
+
"empty_output_struc": "<<structure>>",
|
| 9 |
+
"entity_id": "42c714885d17f6c0fcfebebd171b5ed7d7e77a56cf9c4983d9ff9ff90995bd1c",
|
| 10 |
+
"flat_output_layout": "<<atom-layout>>",
|
| 11 |
+
"frames_mask": "e8a48532fba32c318f7d809fae3ea0999baa01376b29d94ef3c27d82f12f6a90",
|
| 12 |
+
"is_dna": "1d83518b897b14e2943990eff655838246cc0207a7c95a5f3dfccc2e395f8bbf",
|
| 13 |
+
"is_ligand": "cfa4e080dc2885de94224db5075c2feb0805567d31e8898abdebaebc6646ce12",
|
| 14 |
+
"is_nonstandard_polymer_chain": "1d83518b897b14e2943990eff655838246cc0207a7c95a5f3dfccc2e395f8bbf",
|
| 15 |
+
"is_protein": "569b0e93b5f77c1a9d430b643f29e600c7db6f44ded72b96ab1dd25351d26075",
|
| 16 |
+
"is_rna": "1d83518b897b14e2943990eff655838246cc0207a7c95a5f3dfccc2e395f8bbf",
|
| 17 |
+
"is_water": "1d83518b897b14e2943990eff655838246cc0207a7c95a5f3dfccc2e395f8bbf",
|
| 18 |
+
"ligand_ligand_bonds": "<<None>>",
|
| 19 |
+
"msa": "871c93669d8a7dd046f8ba6a1ea7b9fc52e1a2e040c8d9bdc4ae73a77f95d3f7",
|
| 20 |
+
"msa_mask": "13a46a8a2c5305d2a07bb9587ad092d97749d2b2a2d10ad5d64474a4f0f4c803",
|
| 21 |
+
"num_alignments": "26b25d457597a7b0463f9620f666dd10aa2c4373a505967c7c8d70922a2d6ece",
|
| 22 |
+
"polymer_ligand_bonds": "<<None>>",
|
| 23 |
+
"pred_dense_atom_mask": "1e388e40167a4d31291903d74c98544868d0dc574706cdfd259ddd65f56d2993",
|
| 24 |
+
"profile": "6ec7da33d5f9801357ca6c82725416ef59025c7a8810bfd67fed2262845b480b",
|
| 25 |
+
"queries_to_keys:gather_idxs": "e0a2fd867fbae573b5613a98ee037eeb575cc5aa3285db2fe5158cda0e8c49cd",
|
| 26 |
+
"queries_to_keys:gather_mask": "7ddcbfda2904f013d9ab73c55517ac933ecb3dbfbfab9bb351ee43b5fd66e54e",
|
| 27 |
+
"queries_to_keys:input_shape": "cf801b14d3da833c486e3d73e355c3c2068523012b42c2b17decc45dbd8b9972",
|
| 28 |
+
"queries_to_token_atoms:gather_idxs": "3c2d0028564167c93b2f33e877974d45756c1e2e8934270c024fc5f1e85fcf14",
|
| 29 |
+
"queries_to_token_atoms:gather_mask": "1e388e40167a4d31291903d74c98544868d0dc574706cdfd259ddd65f56d2993",
|
| 30 |
+
"queries_to_token_atoms:input_shape": "cf801b14d3da833c486e3d73e355c3c2068523012b42c2b17decc45dbd8b9972",
|
| 31 |
+
"ref_atom_name_chars": "043f3242ff4dff04fd36699ccefdff718c57c325f72c71f33f4c4774e75a64dc",
|
| 32 |
+
"ref_charge": "27898ee238963105942db19f27a980c1fe4f7aeb396c1e5ea4e82da3876deef4",
|
| 33 |
+
"ref_element": "cc437747adeea094daf8a0e551be02f406c7e7d9b0a9328a84a59d907c5492b5",
|
| 34 |
+
"ref_mask": "1e388e40167a4d31291903d74c98544868d0dc574706cdfd259ddd65f56d2993",
|
| 35 |
+
"ref_space_uid": "97afd7d9d3ba835731457ef090ba4939d707bb2a270d48fde56369bde8e58e9f",
|
| 36 |
+
"residue_center_index": "dfef3704f73a7ee9a3be86b74e25ecd43e056c76574bc9bb65b6b446eeed87a7",
|
| 37 |
+
"residue_index": "6bf4ea803d0fcd31446e07f6ba9e012f794ced1fe5ad60b7181f66bb92601638",
|
| 38 |
+
"seq_length": "5a667734987b65ef5c4d07bf176148504bcf8378a5a1a0e23a7fa2c1121cc143",
|
| 39 |
+
"seq_mask": "a795c048f28bc4307f8599dc5140fe6e971bce6a34a0349b6c18d6cbb197f75f",
|
| 40 |
+
"sym_id": "5f170600b904a3464c72817993120957c1ce2eec8c2421af02d4912b5e8d8372",
|
| 41 |
+
"template_aatype": "6c5c3e7a5e23f064f1e8791f61bde8fb59ccf837095144b29e6c8e1607081398",
|
| 42 |
+
"template_atom_mask": "8a282b7476e13f6de5afbb52c14ea7baa3434281ed77b542bb790287e8c92e82",
|
| 43 |
+
"template_atom_positions": "b032ac0c813748a81b8d50ce94487c66510a177ad25e84581c7ea5f4b524987f",
|
| 44 |
+
"token_atoms_layout": "<<atom-layout>>",
|
| 45 |
+
"token_atoms_to_polymer_ligand_bonds:gather_idxs": "a0ee989ed2a0a2e3626520afa4032e06144865c8c8f6357293c9f4cd2069eaf2",
|
| 46 |
+
"token_atoms_to_polymer_ligand_bonds:gather_mask": "d13d4a8b3b8add19b5970157f09d00c12cbda4fed4d74d8493156523f7069b66",
|
| 47 |
+
"token_atoms_to_polymer_ligand_bonds:input_shape": "6ed5c8b9711af5b9c7c3d98ba048bed4dfe5974be758f1a632abd746b8278ed2",
|
| 48 |
+
"token_atoms_to_pseudo_beta:gather_idxs": "3fd8de4dd02450c6e249f33de9c6573694f7991e6a36528d6f32b6c6334a4d4f",
|
| 49 |
+
"token_atoms_to_pseudo_beta:gather_mask": "a795c048f28bc4307f8599dc5140fe6e971bce6a34a0349b6c18d6cbb197f75f",
|
| 50 |
+
"token_atoms_to_pseudo_beta:input_shape": "6ed5c8b9711af5b9c7c3d98ba048bed4dfe5974be758f1a632abd746b8278ed2",
|
| 51 |
+
"token_atoms_to_queries:gather_idxs": "50a1708678bb3d848be6fb49816196b13fcac36891817dac585f4a7556a8310e",
|
| 52 |
+
"token_atoms_to_queries:gather_mask": "3f4ac4f311cea0c7f6b8464e225815b791a767c9a8d15f9c7fb488c49f674fa9",
|
| 53 |
+
"token_atoms_to_queries:input_shape": "6ed5c8b9711af5b9c7c3d98ba048bed4dfe5974be758f1a632abd746b8278ed2",
|
| 54 |
+
"token_index": "77627a5d3856b90a27ae1f5bf5aa14754743c03c00a97bab68f4e7961a405454",
|
| 55 |
+
"tokens_to_keys:gather_idxs": "bc16a2a2b81bdbb3fb3ff180d984704b201866a7cdc373fb345a9be417aa246e",
|
| 56 |
+
"tokens_to_keys:gather_mask": "7ddcbfda2904f013d9ab73c55517ac933ecb3dbfbfab9bb351ee43b5fd66e54e",
|
| 57 |
+
"tokens_to_keys:input_shape": "5545412ee9a21a04712910d53fc1447c73ff94a29ddd1268131b4ed30d1dbe07",
|
| 58 |
+
"tokens_to_ligand_ligand_bonds:gather_idxs": "bac3003591bd8ef44d85b82cd4d23191d48496c1992e61d3fca2a37e6ddd34ea",
|
| 59 |
+
"tokens_to_ligand_ligand_bonds:gather_mask": "4d33ec9784aaf54079b4445118c1be26b4a5555e1d6034ccc4182defd86f2068",
|
| 60 |
+
"tokens_to_ligand_ligand_bonds:input_shape": "5545412ee9a21a04712910d53fc1447c73ff94a29ddd1268131b4ed30d1dbe07",
|
| 61 |
+
"tokens_to_polymer_ligand_bonds:gather_idxs": "a0ee989ed2a0a2e3626520afa4032e06144865c8c8f6357293c9f4cd2069eaf2",
|
| 62 |
+
"tokens_to_polymer_ligand_bonds:gather_mask": "d13d4a8b3b8add19b5970157f09d00c12cbda4fed4d74d8493156523f7069b66",
|
| 63 |
+
"tokens_to_polymer_ligand_bonds:input_shape": "5545412ee9a21a04712910d53fc1447c73ff94a29ddd1268131b4ed30d1dbe07",
|
| 64 |
+
"tokens_to_queries:gather_idxs": "f82b61cc7f007a744fc9186107647ff333b598642a681b046d61aef4994931e1",
|
| 65 |
+
"tokens_to_queries:gather_mask": "3f4ac4f311cea0c7f6b8464e225815b791a767c9a8d15f9c7fb488c49f674fa9",
|
| 66 |
+
"tokens_to_queries:input_shape": "5545412ee9a21a04712910d53fc1447c73ff94a29ddd1268131b4ed30d1dbe07"
|
| 67 |
+
}
|
| 68 |
+
]
|
flax_model/alphafold3/test_data/miniature_databases/__init__.py
ADDED
|
File without changes
|
flax_model/alphafold3/test_data/miniature_databases/bfd-first_non_consensus_sequences__subsampled_1000.fasta
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/mgy_clusters__subsampled_1000.fa
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/nt_rna_2023_02_23_clust_seq_id_90_cov_80_rep_seq__subsampled_1000.fasta
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/5y2e.cif
ADDED
|
@@ -0,0 +1,562 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
data_5Y2E
|
| 2 |
+
#
|
| 3 |
+
_entry.id 5Y2E
|
| 4 |
+
#
|
| 5 |
+
loop_
|
| 6 |
+
_chem_comp.formula
|
| 7 |
+
_chem_comp.formula_weight
|
| 8 |
+
_chem_comp.id
|
| 9 |
+
_chem_comp.mon_nstd_flag
|
| 10 |
+
_chem_comp.name
|
| 11 |
+
_chem_comp.pdbx_synonyms
|
| 12 |
+
_chem_comp.type
|
| 13 |
+
"C3 H7 N O2" 89.093 ALA y ALANINE ? "L-peptide linking"
|
| 14 |
+
"C6 H15 N4 O2 1" 175.209 ARG y ARGININE ? "L-peptide linking"
|
| 15 |
+
"C4 H7 N O4" 133.103 ASP y "ASPARTIC ACID" ? "L-peptide linking"
|
| 16 |
+
"C5 H10 N2 O3" 146.144 GLN y GLUTAMINE ? "L-peptide linking"
|
| 17 |
+
"C5 H9 N O4" 147.129 GLU y "GLUTAMIC ACID" ? "L-peptide linking"
|
| 18 |
+
"C2 H5 N O2" 75.067 GLY y GLYCINE ? "peptide linking"
|
| 19 |
+
"C6 H10 N3 O2 1" 156.162 HIS y HISTIDINE ? "L-peptide linking"
|
| 20 |
+
"H2 O" 18.015 HOH . WATER ? non-polymer
|
| 21 |
+
"C6 H13 N O2" 131.173 ILE y ISOLEUCINE ? "L-peptide linking"
|
| 22 |
+
"C6 H13 N O2" 131.173 LEU y LEUCINE ? "L-peptide linking"
|
| 23 |
+
"C6 H15 N2 O2 1" 147.195 LYS y LYSINE ? "L-peptide linking"
|
| 24 |
+
"C5 H11 N O2 S" 149.211 MET y METHIONINE ? "L-peptide linking"
|
| 25 |
+
"C4 H9 N O3" 119.119 THR y THREONINE ? "L-peptide linking"
|
| 26 |
+
"C5 H11 N O2" 117.146 VAL y VALINE ? "L-peptide linking"
|
| 27 |
+
#
|
| 28 |
+
_entity.id 1
|
| 29 |
+
_entity.pdbx_description "Non-structural glycoprotein 4"
|
| 30 |
+
_entity.type polymer
|
| 31 |
+
#
|
| 32 |
+
_entity_poly.entity_id 1
|
| 33 |
+
_entity_poly.pdbx_strand_id A
|
| 34 |
+
_entity_poly.type polypeptide(L)
|
| 35 |
+
#
|
| 36 |
+
loop_
|
| 37 |
+
_entity_poly_seq.entity_id
|
| 38 |
+
_entity_poly_seq.hetero
|
| 39 |
+
_entity_poly_seq.mon_id
|
| 40 |
+
_entity_poly_seq.num
|
| 41 |
+
1 n MET 1
|
| 42 |
+
1 n ILE 2
|
| 43 |
+
1 n GLU 3
|
| 44 |
+
1 n LYS 4
|
| 45 |
+
1 n GLN 5
|
| 46 |
+
1 n MET 6
|
| 47 |
+
1 n ASP 7
|
| 48 |
+
1 n ARG 8
|
| 49 |
+
1 n VAL 9
|
| 50 |
+
1 n VAL 10
|
| 51 |
+
1 n LYS 11
|
| 52 |
+
1 n GLU 12
|
| 53 |
+
1 n MET 13
|
| 54 |
+
1 n ARG 14
|
| 55 |
+
1 n ARG 15
|
| 56 |
+
1 n GLN 16
|
| 57 |
+
1 n LEU 17
|
| 58 |
+
1 n GLU 18
|
| 59 |
+
1 n MET 19
|
| 60 |
+
1 n ILE 20
|
| 61 |
+
1 n ASP 21
|
| 62 |
+
1 n LYS 22
|
| 63 |
+
1 n LEU 23
|
| 64 |
+
1 n THR 24
|
| 65 |
+
1 n THR 25
|
| 66 |
+
1 n ARG 26
|
| 67 |
+
1 n GLY 27
|
| 68 |
+
1 n ILE 28
|
| 69 |
+
1 n GLU 29
|
| 70 |
+
1 n GLN 30
|
| 71 |
+
1 n VAL 31
|
| 72 |
+
1 n GLU 32
|
| 73 |
+
1 n LEU 33
|
| 74 |
+
1 n LEU 34
|
| 75 |
+
1 n LYS 35
|
| 76 |
+
1 n ARG 36
|
| 77 |
+
1 n ILE 37
|
| 78 |
+
1 n HIS 38
|
| 79 |
+
1 n ASP 39
|
| 80 |
+
1 n LYS 40
|
| 81 |
+
1 n LEU 41
|
| 82 |
+
1 n MET 42
|
| 83 |
+
1 n ILE 43
|
| 84 |
+
1 n ARG 44
|
| 85 |
+
1 n ALA 45
|
| 86 |
+
1 n VAL 46
|
| 87 |
+
1 n ASP 47
|
| 88 |
+
#
|
| 89 |
+
_exptl.method "X-RAY DIFFRACTION"
|
| 90 |
+
#
|
| 91 |
+
_pdbx_audit_revision_history.revision_date 2018-03-14
|
| 92 |
+
#
|
| 93 |
+
_pdbx_database_status.recvd_initial_deposition_date 2018-03-14
|
| 94 |
+
#
|
| 95 |
+
loop_
|
| 96 |
+
_pdbx_poly_seq_scheme.asym_id
|
| 97 |
+
_pdbx_poly_seq_scheme.auth_seq_num
|
| 98 |
+
_pdbx_poly_seq_scheme.entity_id
|
| 99 |
+
_pdbx_poly_seq_scheme.hetero
|
| 100 |
+
_pdbx_poly_seq_scheme.mon_id
|
| 101 |
+
_pdbx_poly_seq_scheme.pdb_ins_code
|
| 102 |
+
_pdbx_poly_seq_scheme.pdb_seq_num
|
| 103 |
+
_pdbx_poly_seq_scheme.pdb_strand_id
|
| 104 |
+
_pdbx_poly_seq_scheme.seq_id
|
| 105 |
+
B 94 1 n MET . 94 A 1
|
| 106 |
+
B 95 1 n ILE . 95 A 2
|
| 107 |
+
B 96 1 n GLU . 96 A 3
|
| 108 |
+
B 97 1 n LYS . 97 A 4
|
| 109 |
+
B 98 1 n GLN . 98 A 5
|
| 110 |
+
B 99 1 n MET . 99 A 6
|
| 111 |
+
B 100 1 n ASP . 100 A 7
|
| 112 |
+
B 101 1 n ARG . 101 A 8
|
| 113 |
+
B 102 1 n VAL . 102 A 9
|
| 114 |
+
B 103 1 n VAL . 103 A 10
|
| 115 |
+
B 104 1 n LYS . 104 A 11
|
| 116 |
+
B 105 1 n GLU . 105 A 12
|
| 117 |
+
B 106 1 n MET . 106 A 13
|
| 118 |
+
B 107 1 n ARG . 107 A 14
|
| 119 |
+
B 108 1 n ARG . 108 A 15
|
| 120 |
+
B 109 1 n GLN . 109 A 16
|
| 121 |
+
B 110 1 n LEU . 110 A 17
|
| 122 |
+
B 111 1 n GLU . 111 A 18
|
| 123 |
+
B 112 1 n MET . 112 A 19
|
| 124 |
+
B 113 1 n ILE . 113 A 20
|
| 125 |
+
B 114 1 n ASP . 114 A 21
|
| 126 |
+
B 115 1 n LYS . 115 A 22
|
| 127 |
+
B 116 1 n LEU . 116 A 23
|
| 128 |
+
B 117 1 n THR . 117 A 24
|
| 129 |
+
B 118 1 n THR . 118 A 25
|
| 130 |
+
B 119 1 n ARG . 119 A 26
|
| 131 |
+
B 120 1 n GLY . 120 A 27
|
| 132 |
+
B 121 1 n ILE . 121 A 28
|
| 133 |
+
B 122 1 n GLU . 122 A 29
|
| 134 |
+
B 123 1 n GLN . 123 A 30
|
| 135 |
+
B 124 1 n VAL . 124 A 31
|
| 136 |
+
B 125 1 n GLU . 125 A 32
|
| 137 |
+
B 126 1 n LEU . 126 A 33
|
| 138 |
+
B 127 1 n LEU . 127 A 34
|
| 139 |
+
B 128 1 n LYS . 128 A 35
|
| 140 |
+
B 129 1 n ARG . 129 A 36
|
| 141 |
+
B 130 1 n ILE . 130 A 37
|
| 142 |
+
B 131 1 n HIS . 131 A 38
|
| 143 |
+
B 132 1 n ASP . 132 A 39
|
| 144 |
+
B 133 1 n LYS . 133 A 40
|
| 145 |
+
B 134 1 n LEU . 134 A 41
|
| 146 |
+
B 135 1 n MET . 135 A 42
|
| 147 |
+
B 136 1 n ILE . 136 A 43
|
| 148 |
+
B 137 1 n ARG . 137 A 44
|
| 149 |
+
B 138 1 n ALA . 138 A 45
|
| 150 |
+
B ? 1 n VAL . 139 A 46
|
| 151 |
+
B ? 1 n ASP . 140 A 47
|
| 152 |
+
#
|
| 153 |
+
_pdbx_struct_assembly.details author_and_software_defined_assembly
|
| 154 |
+
_pdbx_struct_assembly.id 1
|
| 155 |
+
_pdbx_struct_assembly.method_details PISA
|
| 156 |
+
_pdbx_struct_assembly.oligomeric_count 4
|
| 157 |
+
_pdbx_struct_assembly.oligomeric_details tetrameric
|
| 158 |
+
#
|
| 159 |
+
_pdbx_struct_assembly_gen.assembly_id 1
|
| 160 |
+
_pdbx_struct_assembly_gen.asym_id_list A,B,C,D,E,F,G
|
| 161 |
+
_pdbx_struct_assembly_gen.oper_expression 1
|
| 162 |
+
#
|
| 163 |
+
_pdbx_struct_oper_list.id 1
|
| 164 |
+
_pdbx_struct_oper_list.matrix[1][1] 1.0000000000
|
| 165 |
+
_pdbx_struct_oper_list.matrix[1][2] 0.0000000000
|
| 166 |
+
_pdbx_struct_oper_list.matrix[1][3] 0.0000000000
|
| 167 |
+
_pdbx_struct_oper_list.matrix[2][1] 0.0000000000
|
| 168 |
+
_pdbx_struct_oper_list.matrix[2][2] 1.0000000000
|
| 169 |
+
_pdbx_struct_oper_list.matrix[2][3] 0.0000000000
|
| 170 |
+
_pdbx_struct_oper_list.matrix[3][1] 0.0000000000
|
| 171 |
+
_pdbx_struct_oper_list.matrix[3][2] 0.0000000000
|
| 172 |
+
_pdbx_struct_oper_list.matrix[3][3] 1.0000000000
|
| 173 |
+
_pdbx_struct_oper_list.name 1_555
|
| 174 |
+
_pdbx_struct_oper_list.symmetry_operation x,y,z
|
| 175 |
+
_pdbx_struct_oper_list.type "identity operation"
|
| 176 |
+
_pdbx_struct_oper_list.vector[1] 0.0000000000
|
| 177 |
+
_pdbx_struct_oper_list.vector[2] 0.0000000000
|
| 178 |
+
_pdbx_struct_oper_list.vector[3] 0.0000000000
|
| 179 |
+
#
|
| 180 |
+
_refine.ls_d_res_high 2.70
|
| 181 |
+
#
|
| 182 |
+
_software.classification other
|
| 183 |
+
_software.name "DeepMind Structure Class"
|
| 184 |
+
_software.pdbx_ordinal 1
|
| 185 |
+
_software.version 2.0.0
|
| 186 |
+
#
|
| 187 |
+
_struct_asym.entity_id 1
|
| 188 |
+
_struct_asym.id B
|
| 189 |
+
#
|
| 190 |
+
loop_
|
| 191 |
+
_atom_site.group_PDB
|
| 192 |
+
_atom_site.id
|
| 193 |
+
_atom_site.type_symbol
|
| 194 |
+
_atom_site.label_atom_id
|
| 195 |
+
_atom_site.label_alt_id
|
| 196 |
+
_atom_site.label_comp_id
|
| 197 |
+
_atom_site.label_asym_id
|
| 198 |
+
_atom_site.label_entity_id
|
| 199 |
+
_atom_site.label_seq_id
|
| 200 |
+
_atom_site.pdbx_PDB_ins_code
|
| 201 |
+
_atom_site.Cartn_x
|
| 202 |
+
_atom_site.Cartn_y
|
| 203 |
+
_atom_site.Cartn_z
|
| 204 |
+
_atom_site.occupancy
|
| 205 |
+
_atom_site.B_iso_or_equiv
|
| 206 |
+
_atom_site.auth_seq_id
|
| 207 |
+
_atom_site.auth_asym_id
|
| 208 |
+
_atom_site.pdbx_PDB_model_num
|
| 209 |
+
ATOM 1 N N . MET B 1 1 ? 2.644 6.839 -46.028 1.00 83.71 94 A 1
|
| 210 |
+
ATOM 2 C CA . MET B 1 1 ? 1.400 7.612 -45.825 1.00 86.32 94 A 1
|
| 211 |
+
ATOM 3 C C . MET B 1 1 ? 1.210 7.971 -44.344 1.00 87.15 94 A 1
|
| 212 |
+
ATOM 4 O O . MET B 1 1 ? 1.479 7.188 -43.421 1.00 80.48 94 A 1
|
| 213 |
+
ATOM 5 C CB . MET B 1 1 ? 0.170 6.890 -46.382 1.00 88.07 94 A 1
|
| 214 |
+
ATOM 6 C CG . MET B 1 1 ? -0.124 7.275 -47.840 1.00 91.84 94 A 1
|
| 215 |
+
ATOM 7 S SD . MET B 1 1 ? -1.789 6.807 -48.325 1.00 103.69 94 A 1
|
| 216 |
+
ATOM 8 C CE . MET B 1 1 ? -2.264 8.027 -49.569 1.00 97.89 94 A 1
|
| 217 |
+
ATOM 9 N N . ILE B 1 2 ? 0.696 9.166 -44.185 1.00 87.93 95 A 1
|
| 218 |
+
ATOM 10 C CA . ILE B 1 2 ? 0.364 9.779 -42.948 1.00 84.67 95 A 1
|
| 219 |
+
ATOM 11 C C . ILE B 1 2 ? -0.678 8.946 -42.258 1.00 75.98 95 A 1
|
| 220 |
+
ATOM 12 O O . ILE B 1 2 ? -0.634 8.714 -41.080 1.00 67.98 95 A 1
|
| 221 |
+
ATOM 13 C CB . ILE B 1 2 ? -0.321 11.082 -43.309 1.00 89.99 95 A 1
|
| 222 |
+
ATOM 14 C CG1 . ILE B 1 2 ? 0.696 12.146 -43.577 1.00 94.59 95 A 1
|
| 223 |
+
ATOM 15 C CG2 . ILE B 1 2 ? -1.197 11.546 -42.182 1.00 92.79 95 A 1
|
| 224 |
+
ATOM 16 C CD1 . ILE B 1 2 ? 1.132 12.780 -42.294 1.00 93.36 95 A 1
|
| 225 |
+
ATOM 17 N N . GLU B 1 3 ? -1.625 8.499 -43.046 1.00 71.66 96 A 1
|
| 226 |
+
ATOM 18 C CA . GLU B 1 3 ? -2.745 7.716 -42.585 1.00 68.44 96 A 1
|
| 227 |
+
ATOM 19 C C . GLU B 1 3 ? -2.273 6.463 -41.883 1.00 69.98 96 A 1
|
| 228 |
+
ATOM 20 O O . GLU B 1 3 ? -2.890 6.024 -40.946 1.00 67.88 96 A 1
|
| 229 |
+
ATOM 21 C CB . GLU B 1 3 ? -3.613 7.332 -43.745 1.00 73.44 96 A 1
|
| 230 |
+
ATOM 22 C CG . GLU B 1 3 ? -4.382 8.485 -44.320 1.00 87.42 96 A 1
|
| 231 |
+
ATOM 23 C CD . GLU B 1 3 ? -3.735 9.039 -45.551 1.00 89.38 96 A 1
|
| 232 |
+
ATOM 24 O OE1 . GLU B 1 3 ? -4.454 9.413 -46.477 1.00 97.81 96 A 1
|
| 233 |
+
ATOM 25 O OE2 . GLU B 1 3 ? -2.511 9.105 -45.593 1.00 88.14 96 A 1
|
| 234 |
+
ATOM 26 N N . LYS B 1 4 ? -1.212 5.844 -42.364 1.00 71.45 97 A 1
|
| 235 |
+
ATOM 27 C CA . LYS B 1 4 ? -0.676 4.669 -41.671 1.00 72.76 97 A 1
|
| 236 |
+
ATOM 28 C C . LYS B 1 4 ? 0.097 5.062 -40.408 1.00 74.11 97 A 1
|
| 237 |
+
ATOM 29 O O . LYS B 1 4 ? 0.209 4.268 -39.462 1.00 77.84 97 A 1
|
| 238 |
+
ATOM 30 C CB . LYS B 1 4 ? 0.197 3.807 -42.578 1.00 66.63 97 A 1
|
| 239 |
+
ATOM 31 N N . GLN B 1 5 ? 0.624 6.270 -40.364 1.00 72.03 98 A 1
|
| 240 |
+
ATOM 32 C CA . GLN B 1 5 ? 1.295 6.749 -39.158 1.00 65.60 98 A 1
|
| 241 |
+
ATOM 33 C C . GLN B 1 5 ? 0.255 7.097 -38.099 1.00 58.64 98 A 1
|
| 242 |
+
ATOM 34 O O . GLN B 1 5 ? 0.462 6.888 -36.942 1.00 52.26 98 A 1
|
| 243 |
+
ATOM 35 C CB . GLN B 1 5 ? 2.143 7.976 -39.487 1.00 63.76 98 A 1
|
| 244 |
+
ATOM 36 N N . MET B 1 6 ? -0.861 7.648 -38.542 1.00 49.04 99 A 1
|
| 245 |
+
ATOM 37 C CA . MET B 1 6 ? -1.953 7.954 -37.679 1.00 45.66 99 A 1
|
| 246 |
+
ATOM 38 C C . MET B 1 6 ? -2.486 6.679 -37.100 1.00 50.63 99 A 1
|
| 247 |
+
ATOM 39 O O . MET B 1 6 ? -2.882 6.643 -35.948 1.00 50.11 99 A 1
|
| 248 |
+
ATOM 40 C CB . MET B 1 6 ? -3.050 8.640 -38.449 1.00 42.97 99 A 1
|
| 249 |
+
ATOM 41 C CG . MET B 1 6 ? -4.395 8.703 -37.753 1.00 42.67 99 A 1
|
| 250 |
+
ATOM 42 S SD . MET B 1 6 ? -5.430 9.916 -38.524 1.00 47.21 99 A 1
|
| 251 |
+
ATOM 43 C CE . MET B 1 6 ? -6.803 9.938 -37.397 1.00 48.85 99 A 1
|
| 252 |
+
ATOM 44 N N . ASP B 1 7 ? -2.531 5.622 -37.894 1.00 56.67 100 A 1
|
| 253 |
+
ATOM 45 C CA . ASP B 1 7 ? -3.070 4.383 -37.401 1.00 55.17 100 A 1
|
| 254 |
+
ATOM 46 C C . ASP B 1 7 ? -2.223 3.846 -36.257 1.00 53.54 100 A 1
|
| 255 |
+
ATOM 47 O O . ASP B 1 7 ? -2.785 3.365 -35.256 1.00 47.69 100 A 1
|
| 256 |
+
ATOM 48 C CB . ASP B 1 7 ? -3.067 3.354 -38.520 1.00 57.94 100 A 1
|
| 257 |
+
ATOM 49 C CG . ASP B 1 7 ? -3.936 2.164 -38.236 1.00 62.42 100 A 1
|
| 258 |
+
ATOM 50 O OD1 . ASP B 1 7 ? -5.111 2.416 -37.949 1.00 67.59 100 A 1
|
| 259 |
+
ATOM 51 O OD2 . ASP B 1 7 ? -3.401 1.020 -38.206 1.00 61.64 100 A 1
|
| 260 |
+
ATOM 52 N N . ARG B 1 8 ? -0.900 3.909 -36.428 1.00 54.78 101 A 1
|
| 261 |
+
ATOM 53 C CA . ARG B 1 8 ? -0.002 3.384 -35.432 1.00 61.23 101 A 1
|
| 262 |
+
ATOM 54 C C . ARG B 1 8 ? -0.168 4.177 -34.127 1.00 63.20 101 A 1
|
| 263 |
+
ATOM 55 O O . ARG B 1 8 ? -0.017 3.620 -33.077 1.00 67.94 101 A 1
|
| 264 |
+
ATOM 56 C CB . ARG B 1 8 ? 1.484 3.327 -35.943 1.00 64.73 101 A 1
|
| 265 |
+
ATOM 57 C CG . ARG B 1 8 ? 2.403 4.541 -35.635 1.00 73.16 101 A 1
|
| 266 |
+
ATOM 58 N N . VAL B 1 9 ? -0.406 5.483 -34.222 1.00 63.14 102 A 1
|
| 267 |
+
ATOM 59 C CA . VAL B 1 9 ? -0.546 6.334 -33.061 1.00 59.81 102 A 1
|
| 268 |
+
ATOM 60 C C . VAL B 1 9 ? -1.853 6.121 -32.347 1.00 55.82 102 A 1
|
| 269 |
+
ATOM 61 O O . VAL B 1 9 ? -1.880 6.066 -31.150 1.00 48.46 102 A 1
|
| 270 |
+
ATOM 62 C CB . VAL B 1 9 ? -0.421 7.813 -33.454 1.00 60.39 102 A 1
|
| 271 |
+
ATOM 63 C CG1 . VAL B 1 9 ? -0.731 8.703 -32.272 1.00 60.03 102 A 1
|
| 272 |
+
ATOM 64 C CG2 . VAL B 1 9 ? 0.994 8.091 -33.943 1.00 61.68 102 A 1
|
| 273 |
+
ATOM 65 N N . VAL B 1 10 ? -2.941 6.014 -33.079 1.00 56.18 103 A 1
|
| 274 |
+
ATOM 66 C CA . VAL B 1 10 ? -4.231 5.743 -32.481 1.00 53.53 103 A 1
|
| 275 |
+
ATOM 67 C C . VAL B 1 10 ? -4.236 4.419 -31.704 1.00 52.90 103 A 1
|
| 276 |
+
ATOM 68 O O . VAL B 1 10 ? -4.772 4.355 -30.607 1.00 49.99 103 A 1
|
| 277 |
+
ATOM 69 C CB . VAL B 1 10 ? -5.317 5.742 -33.553 1.00 51.75 103 A 1
|
| 278 |
+
ATOM 70 C CG1 . VAL B 1 10 ? -6.606 5.137 -33.045 1.00 52.18 103 A 1
|
| 279 |
+
ATOM 71 C CG2 . VAL B 1 10 ? -5.610 7.153 -33.983 1.00 52.67 103 A 1
|
| 280 |
+
ATOM 72 N N . LYS B 1 11 ? -3.601 3.402 -32.243 1.00 55.55 104 A 1
|
| 281 |
+
ATOM 73 C CA . LYS B 1 11 ? -3.521 2.104 -31.626 1.00 56.87 104 A 1
|
| 282 |
+
ATOM 74 C C . LYS B 1 11 ? -2.709 2.164 -30.350 1.00 60.76 104 A 1
|
| 283 |
+
ATOM 75 O O . LYS B 1 11 ? -2.986 1.464 -29.399 1.00 58.80 104 A 1
|
| 284 |
+
ATOM 76 C CB . LYS B 1 11 ? -2.837 1.155 -32.582 1.00 60.72 104 A 1
|
| 285 |
+
ATOM 77 C CG . LYS B 1 11 ? -3.729 0.487 -33.601 1.00 72.80 104 A 1
|
| 286 |
+
ATOM 78 C CD . LYS B 1 11 ? -2.915 -0.472 -34.451 1.00 79.85 104 A 1
|
| 287 |
+
ATOM 79 C CE . LYS B 1 11 ? -3.664 -0.963 -35.666 1.00 84.90 104 A 1
|
| 288 |
+
ATOM 80 N NZ . LYS B 1 11 ? -5.110 -0.693 -35.513 1.00 94.50 104 A 1
|
| 289 |
+
ATOM 81 N N . GLU B 1 12 ? -1.674 2.982 -30.369 1.00 56.70 105 A 1
|
| 290 |
+
ATOM 82 C CA . GLU B 1 12 ? -0.798 3.204 -29.249 1.00 54.71 105 A 1
|
| 291 |
+
ATOM 83 C C . GLU B 1 12 ? -1.507 3.946 -28.155 1.00 52.45 105 A 1
|
| 292 |
+
ATOM 84 O O . GLU B 1 12 ? -1.387 3.608 -27.007 1.00 51.88 105 A 1
|
| 293 |
+
ATOM 85 C CB . GLU B 1 12 ? 0.404 4.036 -29.667 1.00 60.63 105 A 1
|
| 294 |
+
ATOM 86 C CG . GLU B 1 12 ? 1.418 4.261 -28.569 1.00 71.75 105 A 1
|
| 295 |
+
ATOM 87 C CD . GLU B 1 12 ? 2.100 2.985 -28.105 1.00 83.66 105 A 1
|
| 296 |
+
ATOM 88 O OE1 . GLU B 1 12 ? 1.973 1.951 -28.793 1.00 97.71 105 A 1
|
| 297 |
+
ATOM 89 O OE2 . GLU B 1 12 ? 2.729 3.008 -27.039 1.00 91.62 105 A 1
|
| 298 |
+
ATOM 90 N N . MET B 1 13 ? -2.250 4.972 -28.495 1.00 50.99 106 A 1
|
| 299 |
+
ATOM 91 C CA . MET B 1 13 ? -2.993 5.703 -27.508 1.00 53.07 106 A 1
|
| 300 |
+
ATOM 92 C C . MET B 1 13 ? -4.045 4.874 -26.849 1.00 51.54 106 A 1
|
| 301 |
+
ATOM 93 O O . MET B 1 13 ? -4.220 4.974 -25.651 1.00 48.88 106 A 1
|
| 302 |
+
ATOM 94 C CB . MET B 1 13 ? -3.640 6.915 -28.107 1.00 61.60 106 A 1
|
| 303 |
+
ATOM 95 C CG . MET B 1 13 ? -2.651 8.032 -28.402 1.00 65.35 106 A 1
|
| 304 |
+
ATOM 96 S SD . MET B 1 13 ? -3.551 9.590 -28.498 1.00 76.88 106 A 1
|
| 305 |
+
ATOM 97 C CE . MET B 1 13 ? -3.620 9.931 -26.737 1.00 76.03 106 A 1
|
| 306 |
+
ATOM 98 N N . ARG B 1 14 ? -4.714 4.016 -27.571 1.00 53.52 107 A 1
|
| 307 |
+
ATOM 99 C CA . ARG B 1 14 ? -5.703 3.187 -26.952 1.00 50.53 107 A 1
|
| 308 |
+
ATOM 100 C C . ARG B 1 14 ? -5.040 2.268 -25.975 1.00 51.01 107 A 1
|
| 309 |
+
ATOM 101 O O . ARG B 1 14 ? -5.527 2.040 -24.903 1.00 48.89 107 A 1
|
| 310 |
+
ATOM 102 C CB . ARG B 1 14 ? -6.358 2.367 -28.011 1.00 54.79 107 A 1
|
| 311 |
+
ATOM 103 C CG . ARG B 1 14 ? -7.580 1.648 -27.566 1.00 60.71 107 A 1
|
| 312 |
+
ATOM 104 C CD . ARG B 1 14 ? -7.895 0.586 -28.570 1.00 70.83 107 A 1
|
| 313 |
+
ATOM 105 N NE . ARG B 1 14 ? -8.689 1.116 -29.658 1.00 78.79 107 A 1
|
| 314 |
+
ATOM 106 C CZ . ARG B 1 14 ? -8.278 1.182 -30.911 1.00 81.77 107 A 1
|
| 315 |
+
ATOM 107 N NH1 . ARG B 1 14 ? -7.086 0.746 -31.233 1.00 91.09 107 A 1
|
| 316 |
+
ATOM 108 N NH2 . ARG B 1 14 ? -9.071 1.675 -31.832 1.00 79.36 107 A 1
|
| 317 |
+
ATOM 109 N N . ARG B 1 15 ? -3.896 1.754 -26.355 1.00 46.73 108 A 1
|
| 318 |
+
ATOM 110 C CA . ARG B 1 15 ? -3.174 0.827 -25.534 1.00 45.05 108 A 1
|
| 319 |
+
ATOM 111 C C . ARG B 1 15 ? -2.681 1.503 -24.248 1.00 47.85 108 A 1
|
| 320 |
+
ATOM 112 O O . ARG B 1 15 ? -2.752 0.930 -23.189 1.00 50.40 108 A 1
|
| 321 |
+
ATOM 113 C CB . ARG B 1 15 ? -2.063 0.286 -26.404 1.00 50.23 108 A 1
|
| 322 |
+
ATOM 114 C CG . ARG B 1 15 ? -1.165 -0.750 -25.876 1.00 59.06 108 A 1
|
| 323 |
+
ATOM 115 C CD . ARG B 1 15 ? -0.358 -1.317 -27.046 1.00 59.59 108 A 1
|
| 324 |
+
ATOM 116 N NE . ARG B 1 15 ? 0.861 -1.991 -26.583 1.00 65.92 108 A 1
|
| 325 |
+
ATOM 117 N N . GLN B 1 16 ? -2.221 2.739 -24.349 1.00 49.74 109 A 1
|
| 326 |
+
ATOM 118 C CA . GLN B 1 16 ? -1.810 3.511 -23.193 1.00 47.85 109 A 1
|
| 327 |
+
ATOM 119 C C . GLN B 1 16 ? -2.993 3.774 -22.279 1.00 48.41 109 A 1
|
| 328 |
+
ATOM 120 O O . GLN B 1 16 ? -2.898 3.560 -21.091 1.00 46.33 109 A 1
|
| 329 |
+
ATOM 121 C CB . GLN B 1 16 ? -1.209 4.809 -23.611 1.00 49.18 109 A 1
|
| 330 |
+
ATOM 122 C CG . GLN B 1 16 ? 0.208 4.681 -24.112 1.00 53.75 109 A 1
|
| 331 |
+
ATOM 123 C CD . GLN B 1 16 ? 0.618 5.857 -24.974 1.00 61.24 109 A 1
|
| 332 |
+
ATOM 124 O OE1 . GLN B 1 16 ? -0.145 6.791 -25.159 1.00 69.70 109 A 1
|
| 333 |
+
ATOM 125 N NE2 . GLN B 1 16 ? 1.786 5.782 -25.546 1.00 63.00 109 A 1
|
| 334 |
+
ATOM 126 N N . LEU B 1 17 ? -4.098 4.266 -22.817 1.00 45.61 110 A 1
|
| 335 |
+
ATOM 127 C CA . LEU B 1 17 ? -5.278 4.506 -22.010 1.00 41.80 110 A 1
|
| 336 |
+
ATOM 128 C C . LEU B 1 17 ? -5.848 3.244 -21.329 1.00 44.01 110 A 1
|
| 337 |
+
ATOM 129 O O . LEU B 1 17 ? -6.378 3.314 -20.232 1.00 49.63 110 A 1
|
| 338 |
+
ATOM 130 C CB . LEU B 1 17 ? -6.380 5.133 -22.818 1.00 41.83 110 A 1
|
| 339 |
+
ATOM 131 C CG . LEU B 1 17 ? -6.545 6.610 -23.075 1.00 44.57 110 A 1
|
| 340 |
+
ATOM 132 C CD1 . LEU B 1 17 ? -6.481 7.448 -21.815 1.00 46.53 110 A 1
|
| 341 |
+
ATOM 133 C CD2 . LEU B 1 17 ? -5.534 7.076 -24.054 1.00 46.70 110 A 1
|
| 342 |
+
ATOM 134 N N . GLU B 1 18 ? -5.724 2.085 -21.974 1.00 48.92 111 A 1
|
| 343 |
+
ATOM 135 C CA . GLU B 1 18 ? -6.176 0.854 -21.354 1.00 50.45 111 A 1
|
| 344 |
+
ATOM 136 C C . GLU B 1 18 ? -5.278 0.446 -20.173 1.00 50.00 111 A 1
|
| 345 |
+
ATOM 137 O O . GLU B 1 18 ? -5.748 -0.088 -19.155 1.00 52.97 111 A 1
|
| 346 |
+
ATOM 138 C CB . GLU B 1 18 ? -6.361 -0.236 -22.405 1.00 54.05 111 A 1
|
| 347 |
+
ATOM 139 C CG . GLU B 1 18 ? -7.693 -0.095 -23.112 1.00 59.57 111 A 1
|
| 348 |
+
ATOM 140 C CD . GLU B 1 18 ? -7.804 -0.858 -24.438 1.00 68.03 111 A 1
|
| 349 |
+
ATOM 141 O OE1 . GLU B 1 18 ? -6.834 -1.521 -24.893 1.00 73.96 111 A 1
|
| 350 |
+
ATOM 142 O OE2 . GLU B 1 18 ? -8.896 -0.808 -25.069 1.00 73.24 111 A 1
|
| 351 |
+
ATOM 143 N N . MET B 1 19 ? -4.000 0.760 -20.284 1.00 48.79 112 A 1
|
| 352 |
+
ATOM 144 C CA . MET B 1 19 ? -3.094 0.512 -19.186 1.00 52.15 112 A 1
|
| 353 |
+
ATOM 145 C C . MET B 1 19 ? -3.371 1.430 -18.007 1.00 47.91 112 A 1
|
| 354 |
+
ATOM 146 O O . MET B 1 19 ? -3.429 0.986 -16.872 1.00 45.58 112 A 1
|
| 355 |
+
ATOM 147 C CB . MET B 1 19 ? -1.653 0.667 -19.617 1.00 54.11 112 A 1
|
| 356 |
+
ATOM 148 C CG . MET B 1 19 ? -1.053 -0.654 -20.052 1.00 58.96 112 A 1
|
| 357 |
+
ATOM 149 S SD . MET B 1 19 ? 0.471 -0.323 -20.923 1.00 65.09 112 A 1
|
| 358 |
+
ATOM 150 C CE . MET B 1 19 ? 1.501 -0.237 -19.466 1.00 67.56 112 A 1
|
| 359 |
+
ATOM 151 N N . ILE B 1 20 ? -3.541 2.711 -18.297 1.00 43.25 113 A 1
|
| 360 |
+
ATOM 152 C CA . ILE B 1 20 ? -3.900 3.677 -17.287 1.00 40.09 113 A 1
|
| 361 |
+
ATOM 153 C C . ILE B 1 20 ? -5.165 3.240 -16.596 1.00 40.28 113 A 1
|
| 362 |
+
ATOM 154 O O . ILE B 1 20 ? -5.297 3.383 -15.395 1.00 41.67 113 A 1
|
| 363 |
+
ATOM 155 C CB . ILE B 1 20 ? -4.079 5.077 -17.885 1.00 41.26 113 A 1
|
| 364 |
+
ATOM 156 C CG1 . ILE B 1 20 ? -2.700 5.633 -18.275 1.00 39.56 113 A 1
|
| 365 |
+
ATOM 157 C CG2 . ILE B 1 20 ? -4.715 6.029 -16.880 1.00 44.72 113 A 1
|
| 366 |
+
ATOM 158 C CD1 . ILE B 1 20 ? -2.722 6.963 -19.009 1.00 37.40 113 A 1
|
| 367 |
+
ATOM 159 N N . ASP B 1 21 ? -6.096 2.680 -17.346 1.00 41.39 114 A 1
|
| 368 |
+
ATOM 160 C CA . ASP B 1 21 ? -7.302 2.201 -16.728 1.00 46.35 114 A 1
|
| 369 |
+
ATOM 161 C C . ASP B 1 21 ? -7.074 1.044 -15.762 1.00 45.76 114 A 1
|
| 370 |
+
ATOM 162 O O . ASP B 1 21 ? -7.662 1.035 -14.682 1.00 43.56 114 A 1
|
| 371 |
+
ATOM 163 C CB . ASP B 1 21 ? -8.272 1.734 -17.759 1.00 51.71 114 A 1
|
| 372 |
+
ATOM 164 C CG . ASP B 1 21 ? -9.647 1.640 -17.208 1.00 60.74 114 A 1
|
| 373 |
+
ATOM 165 O OD1 . ASP B 1 21 ? -10.153 2.682 -16.742 1.00 68.50 114 A 1
|
| 374 |
+
ATOM 166 O OD2 . ASP B 1 21 ? -10.199 0.528 -17.210 1.00 73.36 114 A 1
|
| 375 |
+
ATOM 167 N N . LYS B 1 22 ? -6.258 0.070 -16.178 1.00 47.51 115 A 1
|
| 376 |
+
ATOM 168 C CA . LYS B 1 22 ? -5.942 -1.062 -15.321 1.00 50.59 115 A 1
|
| 377 |
+
ATOM 169 C C . LYS B 1 22 ? -5.255 -0.563 -14.028 1.00 52.11 115 A 1
|
| 378 |
+
ATOM 170 O O . LYS B 1 22 ? -5.648 -0.941 -12.919 1.00 55.27 115 A 1
|
| 379 |
+
ATOM 171 C CB . LYS B 1 22 ? -5.085 -2.111 -16.025 1.00 52.86 115 A 1
|
| 380 |
+
ATOM 172 C CG . LYS B 1 22 ? -5.829 -3.010 -17.008 1.00 57.80 115 A 1
|
| 381 |
+
ATOM 173 N N . LEU B 1 23 ? -4.266 0.312 -14.176 1.00 48.62 116 A 1
|
| 382 |
+
ATOM 174 C CA . LEU B 1 23 ? -3.594 0.880 -13.039 1.00 44.80 116 A 1
|
| 383 |
+
ATOM 175 C C . LEU B 1 23 ? -4.511 1.665 -12.106 1.00 44.04 116 A 1
|
| 384 |
+
ATOM 176 O O . LEU B 1 23 ? -4.412 1.565 -10.897 1.00 41.22 116 A 1
|
| 385 |
+
ATOM 177 C CB . LEU B 1 23 ? -2.492 1.781 -13.511 1.00 43.26 116 A 1
|
| 386 |
+
ATOM 178 C CG . LEU B 1 23 ? -1.353 1.039 -14.177 1.00 45.18 116 A 1
|
| 387 |
+
ATOM 179 C CD1 . LEU B 1 23 ? -0.449 2.064 -14.839 1.00 45.01 116 A 1
|
| 388 |
+
ATOM 180 C CD2 . LEU B 1 23 ? -0.582 0.210 -13.156 1.00 45.90 116 A 1
|
| 389 |
+
ATOM 181 N N . THR B 1 24 ? -5.402 2.445 -12.674 1.00 49.17 117 A 1
|
| 390 |
+
ATOM 182 C CA . THR B 1 24 ? -6.382 3.155 -11.886 1.00 49.60 117 A 1
|
| 391 |
+
ATOM 183 C C . THR B 1 24 ? -7.250 2.198 -11.085 1.00 51.60 117 A 1
|
| 392 |
+
ATOM 184 O O . THR B 1 24 ? -7.503 2.441 -9.918 1.00 50.82 117 A 1
|
| 393 |
+
ATOM 185 C CB . THR B 1 24 ? -7.248 4.024 -12.811 1.00 54.67 117 A 1
|
| 394 |
+
ATOM 186 O OG1 . THR B 1 24 ? -6.463 5.126 -13.253 1.00 58.01 117 A 1
|
| 395 |
+
ATOM 187 C CG2 . THR B 1 24 ? -8.464 4.559 -12.141 1.00 57.77 117 A 1
|
| 396 |
+
ATOM 188 N N . THR B 1 25 ? -7.718 1.116 -11.704 1.00 53.09 118 A 1
|
| 397 |
+
ATOM 189 C CA . THR B 1 25 ? -8.495 0.117 -10.981 1.00 50.55 118 A 1
|
| 398 |
+
ATOM 190 C C . THR B 1 25 ? -7.709 -0.503 -9.820 1.00 49.50 118 A 1
|
| 399 |
+
ATOM 191 O O . THR B 1 25 ? -8.267 -0.695 -8.720 1.00 50.25 118 A 1
|
| 400 |
+
ATOM 192 C CB . THR B 1 25 ? -8.933 -0.983 -11.947 1.00 53.52 118 A 1
|
| 401 |
+
ATOM 193 O OG1 . THR B 1 25 ? -9.796 -0.396 -12.916 1.00 60.17 118 A 1
|
| 402 |
+
ATOM 194 C CG2 . THR B 1 25 ? -9.619 -2.127 -11.260 1.00 58.18 118 A 1
|
| 403 |
+
ATOM 195 N N . ARG B 1 26 ? -6.447 -0.762 -10.054 1.00 48.62 119 A 1
|
| 404 |
+
ATOM 196 C CA . ARG B 1 26 ? -5.575 -1.319 -9.076 1.00 52.29 119 A 1
|
| 405 |
+
ATOM 197 C C . ARG B 1 26 ? -5.362 -0.349 -7.936 1.00 56.15 119 A 1
|
| 406 |
+
ATOM 198 O O . ARG B 1 26 ? -5.203 -0.758 -6.818 1.00 60.08 119 A 1
|
| 407 |
+
ATOM 199 C CB . ARG B 1 26 ? -4.262 -1.609 -9.738 1.00 57.25 119 A 1
|
| 408 |
+
ATOM 200 C CG . ARG B 1 26 ? -4.341 -2.608 -10.845 1.00 67.09 119 A 1
|
| 409 |
+
ATOM 201 C CD . ARG B 1 26 ? -4.671 -3.974 -10.307 1.00 78.77 119 A 1
|
| 410 |
+
ATOM 202 N NE . ARG B 1 26 ? -4.743 -4.923 -11.390 1.00 95.96 119 A 1
|
| 411 |
+
ATOM 203 C CZ . ARG B 1 26 ? -3.703 -5.558 -11.900 1.00 111.57 119 A 1
|
| 412 |
+
ATOM 204 N NH1 . ARG B 1 26 ? -3.881 -6.412 -12.892 1.00 120.54 119 A 1
|
| 413 |
+
ATOM 205 N NH2 . ARG B 1 26 ? -2.494 -5.350 -11.417 1.00 114.95 119 A 1
|
| 414 |
+
ATOM 206 N N . GLY B 1 27 ? -5.312 0.940 -8.241 1.00 57.29 120 A 1
|
| 415 |
+
ATOM 207 C CA . GLY B 1 27 ? -5.176 2.005 -7.265 1.00 55.03 120 A 1
|
| 416 |
+
ATOM 208 C C . GLY B 1 27 ? -6.391 2.105 -6.381 1.00 51.16 120 A 1
|
| 417 |
+
ATOM 209 O O . GLY B 1 27 ? -6.273 2.252 -5.174 1.00 48.31 120 A 1
|
| 418 |
+
ATOM 210 N N . ILE B 1 28 ? -7.570 1.983 -6.973 1.00 48.29 121 A 1
|
| 419 |
+
ATOM 211 C CA . ILE B 1 28 ? -8.807 2.040 -6.198 1.00 51.59 121 A 1
|
| 420 |
+
ATOM 212 C C . ILE B 1 28 ? -8.893 0.889 -5.227 1.00 54.18 121 A 1
|
| 421 |
+
ATOM 213 O O . ILE B 1 28 ? -9.376 1.068 -4.118 1.00 53.53 121 A 1
|
| 422 |
+
ATOM 214 C CB . ILE B 1 28 ? -10.053 2.141 -7.095 1.00 55.27 121 A 1
|
| 423 |
+
ATOM 215 C CG1 . ILE B 1 28 ? -10.187 3.601 -7.621 1.00 55.95 121 A 1
|
| 424 |
+
ATOM 216 C CG2 . ILE B 1 28 ? -11.306 1.807 -6.320 1.00 61.76 121 A 1
|
| 425 |
+
ATOM 217 C CD1 . ILE B 1 28 ? -11.126 3.822 -8.793 1.00 55.74 121 A 1
|
| 426 |
+
ATOM 218 N N . GLU B 1 29 ? -8.420 -0.273 -5.627 1.00 61.84 122 A 1
|
| 427 |
+
ATOM 219 C CA . GLU B 1 29 ? -8.319 -1.378 -4.700 1.00 67.68 122 A 1
|
| 428 |
+
ATOM 220 C C . GLU B 1 29 ? -7.415 -1.069 -3.537 1.00 65.03 122 A 1
|
| 429 |
+
ATOM 221 O O . GLU B 1 29 ? -7.791 -1.331 -2.393 1.00 64.70 122 A 1
|
| 430 |
+
ATOM 222 C CB . GLU B 1 29 ? -7.868 -2.634 -5.431 1.00 78.78 122 A 1
|
| 431 |
+
ATOM 223 C CG . GLU B 1 29 ? -9.069 -3.428 -5.962 1.00 86.76 122 A 1
|
| 432 |
+
ATOM 224 C CD . GLU B 1 29 ? -8.878 -4.019 -7.353 1.00 87.49 122 A 1
|
| 433 |
+
ATOM 225 O OE1 . GLU B 1 29 ? -7.768 -4.558 -7.636 1.00 84.73 122 A 1
|
| 434 |
+
ATOM 226 O OE2 . GLU B 1 29 ? -9.870 -3.959 -8.121 1.00 77.87 122 A 1
|
| 435 |
+
ATOM 227 N N . GLN B 1 30 ? -6.256 -0.484 -3.829 1.00 59.57 123 A 1
|
| 436 |
+
ATOM 228 C CA . GLN B 1 30 ? -5.315 -0.084 -2.773 1.00 55.23 123 A 1
|
| 437 |
+
ATOM 229 C C . GLN B 1 30 ? -5.910 0.955 -1.841 1.00 51.86 123 A 1
|
| 438 |
+
ATOM 230 O O . GLN B 1 30 ? -5.662 0.942 -0.653 1.00 44.12 123 A 1
|
| 439 |
+
ATOM 231 C CB . GLN B 1 30 ? -4.037 0.514 -3.362 1.00 55.92 123 A 1
|
| 440 |
+
ATOM 232 C CG . GLN B 1 30 ? -3.221 -0.371 -4.262 1.00 61.37 123 A 1
|
| 441 |
+
ATOM 233 C CD . GLN B 1 30 ? -2.863 -1.664 -3.614 1.00 62.35 123 A 1
|
| 442 |
+
ATOM 234 O OE1 . GLN B 1 30 ? -2.326 -1.663 -2.512 1.00 63.09 123 A 1
|
| 443 |
+
ATOM 235 N NE2 . GLN B 1 30 ? -3.188 -2.787 -4.276 1.00 70.63 123 A 1
|
| 444 |
+
ATOM 236 N N . VAL B 1 31 ? -6.703 1.858 -2.386 1.00 57.05 124 A 1
|
| 445 |
+
ATOM 237 C CA . VAL B 1 31 ? -7.323 2.883 -1.569 1.00 56.37 124 A 1
|
| 446 |
+
ATOM 238 C C . VAL B 1 31 ? -8.333 2.246 -0.629 1.00 61.68 124 A 1
|
| 447 |
+
ATOM 239 O O . VAL B 1 31 ? -8.461 2.699 0.470 1.00 58.51 124 A 1
|
| 448 |
+
ATOM 240 C CB . VAL B 1 31 ? -7.969 3.950 -2.456 1.00 57.06 124 A 1
|
| 449 |
+
ATOM 241 C CG1 . VAL B 1 31 ? -9.007 4.756 -1.702 1.00 58.79 124 A 1
|
| 450 |
+
ATOM 242 C CG2 . VAL B 1 31 ? -6.871 4.864 -2.974 1.00 58.78 124 A 1
|
| 451 |
+
ATOM 243 N N . GLU B 1 32 ? -9.044 1.205 -1.068 1.00 67.95 125 A 1
|
| 452 |
+
ATOM 244 C CA . GLU B 1 32 ? -9.940 0.481 -0.175 1.00 64.07 125 A 1
|
| 453 |
+
ATOM 245 C C . GLU B 1 32 ? -9.140 -0.246 0.887 1.00 61.43 125 A 1
|
| 454 |
+
ATOM 246 O O . GLU B 1 32 ? -9.521 -0.248 2.049 1.00 58.85 125 A 1
|
| 455 |
+
ATOM 247 C CB . GLU B 1 32 ? -10.821 -0.511 -0.911 1.00 70.57 125 A 1
|
| 456 |
+
ATOM 248 C CG . GLU B 1 32 ? -11.844 0.047 -1.875 1.00 81.60 125 A 1
|
| 457 |
+
ATOM 249 C CD . GLU B 1 32 ? -12.772 1.105 -1.306 1.00 92.01 125 A 1
|
| 458 |
+
ATOM 250 O OE1 . GLU B 1 32 ? -13.833 0.773 -0.713 1.00 101.96 125 A 1
|
| 459 |
+
ATOM 251 O OE2 . GLU B 1 32 ? -12.392 2.286 -1.482 1.00 95.64 125 A 1
|
| 460 |
+
ATOM 252 N N . LEU B 1 33 ? -8.042 -0.849 0.489 1.00 55.72 126 A 1
|
| 461 |
+
ATOM 253 C CA . LEU B 1 33 ? -7.201 -1.483 1.447 1.00 58.91 126 A 1
|
| 462 |
+
ATOM 254 C C . LEU B 1 33 ? -6.628 -0.487 2.476 1.00 56.58 126 A 1
|
| 463 |
+
ATOM 255 O O . LEU B 1 33 ? -6.271 -0.829 3.592 1.00 59.20 126 A 1
|
| 464 |
+
ATOM 256 C CB . LEU B 1 33 ? -6.089 -2.149 0.676 1.00 63.68 126 A 1
|
| 465 |
+
ATOM 257 C CG . LEU B 1 33 ? -5.181 -3.155 1.283 1.00 71.88 126 A 1
|
| 466 |
+
ATOM 258 C CD1 . LEU B 1 33 ? -4.453 -3.972 0.195 1.00 73.91 126 A 1
|
| 467 |
+
ATOM 259 C CD2 . LEU B 1 33 ? -4.179 -2.480 2.169 1.00 75.78 126 A 1
|
| 468 |
+
ATOM 260 N N . LEU B 1 34 ? -6.482 0.743 2.064 1.00 51.59 127 A 1
|
| 469 |
+
ATOM 261 C CA . LEU B 1 34 ? -6.054 1.821 2.952 1.00 47.43 127 A 1
|
| 470 |
+
ATOM 262 C C . LEU B 1 34 ? -7.162 2.293 3.867 1.00 49.18 127 A 1
|
| 471 |
+
ATOM 263 O O . LEU B 1 34 ? -6.917 2.748 4.956 1.00 48.29 127 A 1
|
| 472 |
+
ATOM 264 C CB . LEU B 1 34 ? -5.537 2.996 2.165 1.00 43.17 127 A 1
|
| 473 |
+
ATOM 265 C CG . LEU B 1 34 ? -4.031 2.968 1.890 1.00 42.73 127 A 1
|
| 474 |
+
ATOM 266 C CD1 . LEU B 1 34 ? -3.630 4.313 1.305 1.00 42.46 127 A 1
|
| 475 |
+
ATOM 267 C CD2 . LEU B 1 34 ? -3.088 2.610 3.005 1.00 43.31 127 A 1
|
| 476 |
+
ATOM 268 N N . LYS B 1 35 ? -8.399 2.214 3.408 1.00 52.51 128 A 1
|
| 477 |
+
ATOM 269 C CA . LYS B 1 35 ? -9.553 2.535 4.233 1.00 52.46 128 A 1
|
| 478 |
+
ATOM 270 C C . LYS B 1 35 ? -9.710 1.492 5.330 1.00 53.78 128 A 1
|
| 479 |
+
ATOM 271 O O . LYS B 1 35 ? -10.040 1.823 6.442 1.00 47.30 128 A 1
|
| 480 |
+
ATOM 272 C CB . LYS B 1 35 ? -10.830 2.641 3.381 1.00 54.62 128 A 1
|
| 481 |
+
ATOM 273 C CG . LYS B 1 35 ? -12.138 2.251 4.078 1.00 59.22 128 A 1
|
| 482 |
+
ATOM 274 N N . ARG B 1 36 ? -9.454 0.236 4.997 1.00 56.56 129 A 1
|
| 483 |
+
ATOM 275 C CA . ARG B 1 36 ? -9.471 -0.853 5.953 1.00 60.75 129 A 1
|
| 484 |
+
ATOM 276 C C . ARG B 1 36 ? -8.392 -0.650 7.014 1.00 59.48 129 A 1
|
| 485 |
+
ATOM 277 O O . ARG B 1 36 ? -8.620 -0.927 8.185 1.00 63.52 129 A 1
|
| 486 |
+
ATOM 278 C CB . ARG B 1 36 ? -9.292 -2.210 5.247 1.00 65.76 129 A 1
|
| 487 |
+
ATOM 279 C CG . ARG B 1 36 ? -10.535 -2.769 4.547 1.00 68.71 129 A 1
|
| 488 |
+
ATOM 280 C CD . ARG B 1 36 ? -10.167 -3.835 3.488 1.00 67.67 129 A 1
|
| 489 |
+
ATOM 281 N N . ILE B 1 37 ? -7.221 -0.161 6.611 1.00 54.56 130 A 1
|
| 490 |
+
ATOM 282 C CA . ILE B 1 37 ? -6.140 0.129 7.539 1.00 49.62 130 A 1
|
| 491 |
+
ATOM 283 C C . ILE B 1 37 ? -6.541 1.250 8.466 1.00 49.00 130 A 1
|
| 492 |
+
ATOM 284 O O . ILE B 1 37 ? -6.319 1.155 9.647 1.00 47.20 130 A 1
|
| 493 |
+
ATOM 285 C CB . ILE B 1 37 ? -4.839 0.472 6.806 1.00 51.01 130 A 1
|
| 494 |
+
ATOM 286 C CG1 . ILE B 1 37 ? -4.243 -0.830 6.231 1.00 57.41 130 A 1
|
| 495 |
+
ATOM 287 C CG2 . ILE B 1 37 ? -3.851 1.181 7.755 1.00 49.06 130 A 1
|
| 496 |
+
ATOM 288 C CD1 . ILE B 1 37 ? -2.922 -0.695 5.533 1.00 59.59 130 A 1
|
| 497 |
+
ATOM 289 N N . HIS B 1 38 ? -7.179 2.276 7.957 1.00 50.21 131 A 1
|
| 498 |
+
ATOM 290 C CA . HIS B 1 38 ? -7.618 3.356 8.797 1.00 53.53 131 A 1
|
| 499 |
+
ATOM 291 C C . HIS B 1 38 ? -8.670 2.891 9.780 1.00 62.35 131 A 1
|
| 500 |
+
ATOM 292 O O . HIS B 1 38 ? -8.744 3.378 10.880 1.00 61.76 131 A 1
|
| 501 |
+
ATOM 293 C CB . HIS B 1 38 ? -8.175 4.452 7.947 1.00 51.42 131 A 1
|
| 502 |
+
ATOM 294 C CG . HIS B 1 38 ? -9.034 5.412 8.688 1.00 54.14 131 A 1
|
| 503 |
+
ATOM 295 N ND1 . HIS B 1 38 ? -10.380 5.221 8.850 1.00 59.92 131 A 1
|
| 504 |
+
ATOM 296 C CD2 . HIS B 1 38 ? -8.749 6.586 9.283 1.00 55.36 131 A 1
|
| 505 |
+
ATOM 297 C CE1 . HIS B 1 38 ? -10.887 6.229 9.522 1.00 62.46 131 A 1
|
| 506 |
+
ATOM 298 N NE2 . HIS B 1 38 ? -9.918 7.073 9.795 1.00 61.48 131 A 1
|
| 507 |
+
ATOM 299 N N . ASP B 1 39 ? -9.476 1.928 9.394 1.00 63.84 132 A 1
|
| 508 |
+
ATOM 300 C CA . ASP B 1 39 ? -10.480 1.421 10.286 1.00 65.95 132 A 1
|
| 509 |
+
ATOM 301 C C . ASP B 1 39 ? -9.837 0.648 11.420 1.00 61.61 132 A 1
|
| 510 |
+
ATOM 302 O O . ASP B 1 39 ? -10.164 0.840 12.551 1.00 56.16 132 A 1
|
| 511 |
+
ATOM 303 C CB . ASP B 1 39 ? -11.456 0.577 9.509 1.00 73.60 132 A 1
|
| 512 |
+
ATOM 304 C CG . ASP B 1 39 ? -12.373 1.404 8.658 1.00 76.60 132 A 1
|
| 513 |
+
ATOM 305 O OD1 . ASP B 1 39 ? -12.277 2.631 8.703 1.00 70.60 132 A 1
|
| 514 |
+
ATOM 306 O OD2 . ASP B 1 39 ? -13.195 0.833 7.937 1.00 81.44 132 A 1
|
| 515 |
+
ATOM 307 N N . LYS B 1 40 ? -8.926 -0.245 11.106 1.00 59.87 133 A 1
|
| 516 |
+
ATOM 308 C CA . LYS B 1 40 ? -8.191 -0.985 12.129 1.00 59.13 133 A 1
|
| 517 |
+
ATOM 309 C C . LYS B 1 40 ? -7.573 -0.021 13.157 1.00 58.88 133 A 1
|
| 518 |
+
ATOM 310 O O . LYS B 1 40 ? -7.579 -0.267 14.361 1.00 63.83 133 A 1
|
| 519 |
+
ATOM 311 C CB . LYS B 1 40 ? -7.093 -1.864 11.503 1.00 58.69 133 A 1
|
| 520 |
+
ATOM 312 C CG . LYS B 1 40 ? -7.577 -3.018 10.646 1.00 62.42 133 A 1
|
| 521 |
+
ATOM 313 C CD . LYS B 1 40 ? -6.463 -3.844 9.987 1.00 62.93 133 A 1
|
| 522 |
+
ATOM 314 N N . LEU B 1 41 ? -7.038 1.086 12.674 1.00 60.19 134 A 1
|
| 523 |
+
ATOM 315 C CA . LEU B 1 41 ? -6.454 2.092 13.561 1.00 62.93 134 A 1
|
| 524 |
+
ATOM 316 C C . LEU B 1 41 ? -7.487 2.707 14.452 1.00 63.64 134 A 1
|
| 525 |
+
ATOM 317 O O . LEU B 1 41 ? -7.205 2.982 15.605 1.00 73.06 134 A 1
|
| 526 |
+
ATOM 318 C CB . LEU B 1 41 ? -5.765 3.197 12.764 1.00 64.98 134 A 1
|
| 527 |
+
ATOM 319 C CG . LEU B 1 41 ? -4.531 2.611 12.036 1.00 68.88 134 A 1
|
| 528 |
+
ATOM 320 C CD1 . LEU B 1 41 ? -4.332 3.201 10.638 1.00 78.49 134 A 1
|
| 529 |
+
ATOM 321 C CD2 . LEU B 1 41 ? -3.301 2.685 12.900 1.00 67.40 134 A 1
|
| 530 |
+
ATOM 322 N N . MET B 1 42 ? -8.669 2.955 13.913 1.00 63.76 135 A 1
|
| 531 |
+
ATOM 323 C CA . MET B 1 42 ? -9.752 3.512 14.704 1.00 67.57 135 A 1
|
| 532 |
+
ATOM 324 C C . MET B 1 42 ? -10.186 2.561 15.817 1.00 72.44 135 A 1
|
| 533 |
+
ATOM 325 O O . MET B 1 42 ? -10.413 2.985 16.975 1.00 66.48 135 A 1
|
| 534 |
+
ATOM 326 C CB . MET B 1 42 ? -10.932 3.853 13.816 1.00 69.82 135 A 1
|
| 535 |
+
ATOM 327 C CG . MET B 1 42 ? -10.710 5.112 13.020 1.00 74.54 135 A 1
|
| 536 |
+
ATOM 328 S SD . MET B 1 42 ? -10.062 6.547 13.958 1.00 82.27 135 A 1
|
| 537 |
+
ATOM 329 C CE . MET B 1 42 ? -11.073 6.663 15.446 1.00 83.33 135 A 1
|
| 538 |
+
ATOM 330 N N . ILE B 1 43 ? -10.271 1.274 15.477 1.00 81.93 136 A 1
|
| 539 |
+
ATOM 331 C CA . ILE B 1 43 ? -10.594 0.243 16.446 1.00 79.15 136 A 1
|
| 540 |
+
ATOM 332 C C . ILE B 1 43 ? -9.526 0.183 17.546 1.00 79.65 136 A 1
|
| 541 |
+
ATOM 333 O O . ILE B 1 43 ? -9.854 0.128 18.719 1.00 82.01 136 A 1
|
| 542 |
+
ATOM 334 C CB . ILE B 1 43 ? -10.781 -1.129 15.738 1.00 80.39 136 A 1
|
| 543 |
+
ATOM 335 C CG1 . ILE B 1 43 ? -12.176 -1.237 15.090 1.00 78.84 136 A 1
|
| 544 |
+
ATOM 336 C CG2 . ILE B 1 43 ? -10.586 -2.294 16.708 1.00 84.53 136 A 1
|
| 545 |
+
ATOM 337 C CD1 . ILE B 1 43 ? -12.480 -0.642 13.720 1.00 74.74 136 A 1
|
| 546 |
+
ATOM 338 N N . ARG B 1 44 ? -8.250 0.200 17.158 1.00 85.15 137 A 1
|
| 547 |
+
ATOM 339 C CA . ARG B 1 44 ? -7.131 0.216 18.111 1.00 90.78 137 A 1
|
| 548 |
+
ATOM 340 C C . ARG B 1 44 ? -7.103 1.498 18.957 1.00 91.00 137 A 1
|
| 549 |
+
ATOM 341 O O . ARG B 1 44 ? -6.632 1.453 20.068 1.00 96.79 137 A 1
|
| 550 |
+
ATOM 342 C CB . ARG B 1 44 ? -5.803 0.033 17.373 1.00 95.82 137 A 1
|
| 551 |
+
ATOM 343 C CG . ARG B 1 44 ? -4.883 -1.005 17.902 1.00 101.09 137 A 1
|
| 552 |
+
ATOM 344 C CD . ARG B 1 44 ? -3.772 -1.099 16.880 1.00 107.64 137 A 1
|
| 553 |
+
ATOM 345 N NE . ARG B 1 44 ? -2.978 -2.299 17.060 1.00 124.71 137 A 1
|
| 554 |
+
ATOM 346 C CZ . ARG B 1 44 ? -2.237 -2.882 16.112 1.00 137.30 137 A 1
|
| 555 |
+
ATOM 347 N NH1 . ARG B 1 44 ? -2.186 -2.387 14.871 1.00 128.35 137 A 1
|
| 556 |
+
ATOM 348 N NH2 . ARG B 1 44 ? -1.533 -3.990 16.400 1.00 147.87 137 A 1
|
| 557 |
+
ATOM 349 N N . ALA B 1 45 ? -7.688 2.601 18.506 1.00 92.41 138 A 1
|
| 558 |
+
ATOM 350 C CA . ALA B 1 45 ? -7.783 3.810 19.381 1.00 96.29 138 A 1
|
| 559 |
+
ATOM 351 C C . ALA B 1 45 ? -8.773 4.837 18.851 1.00 95.46 138 A 1
|
| 560 |
+
ATOM 352 O O . ALA B 1 45 ? -8.386 5.847 18.235 1.00 81.53 138 A 1
|
| 561 |
+
ATOM 353 C CB . ALA B 1 45 ? -6.408 4.475 19.603 1.00 97.91 138 A 1
|
| 562 |
+
#
|
flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/6s61.cif
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/6ydw.cif
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/7rye.cif
ADDED
|
@@ -0,0 +1,893 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
data_7RYE
|
| 2 |
+
#
|
| 3 |
+
_entry.id 7RYE
|
| 4 |
+
#
|
| 5 |
+
loop_
|
| 6 |
+
_chem_comp.formula
|
| 7 |
+
_chem_comp.formula_weight
|
| 8 |
+
_chem_comp.id
|
| 9 |
+
_chem_comp.mon_nstd_flag
|
| 10 |
+
_chem_comp.name
|
| 11 |
+
_chem_comp.pdbx_synonyms
|
| 12 |
+
_chem_comp.type
|
| 13 |
+
"C3 H7 N O2" 89.093 ALA y ALANINE ? "L-peptide linking"
|
| 14 |
+
"C6 H15 N4 O2 1" 175.209 ARG y ARGININE ? "L-peptide linking"
|
| 15 |
+
"C4 H8 N2 O3" 132.118 ASN y ASPARAGINE ? "L-peptide linking"
|
| 16 |
+
"C4 H7 N O4" 133.103 ASP y "ASPARTIC ACID" ? "L-peptide linking"
|
| 17 |
+
"C3 H7 N O2 S" 121.158 CYS y CYSTEINE ? "L-peptide linking"
|
| 18 |
+
"C5 H10 N2 O3" 146.144 GLN y GLUTAMINE ? "L-peptide linking"
|
| 19 |
+
"C5 H9 N O4" 147.129 GLU y "GLUTAMIC ACID" ? "L-peptide linking"
|
| 20 |
+
"C2 H5 N O2" 75.067 GLY y GLYCINE ? "peptide linking"
|
| 21 |
+
"C6 H10 N3 O2 1" 156.162 HIS y HISTIDINE ? "L-peptide linking"
|
| 22 |
+
"C6 H13 N O2" 131.173 ILE y ISOLEUCINE ? "L-peptide linking"
|
| 23 |
+
"C6 H13 N O2" 131.173 LEU y LEUCINE ? "L-peptide linking"
|
| 24 |
+
"C6 H15 N2 O2 1" 147.195 LYS y LYSINE ? "L-peptide linking"
|
| 25 |
+
"C5 H11 N O2 S" 149.211 MET y METHIONINE ? "L-peptide linking"
|
| 26 |
+
"C9 H11 N O2" 165.189 PHE y PHENYLALANINE ? "L-peptide linking"
|
| 27 |
+
"C5 H9 N O2" 115.130 PRO y PROLINE ? "L-peptide linking"
|
| 28 |
+
"C3 H7 N O3" 105.093 SER y SERINE ? "L-peptide linking"
|
| 29 |
+
"C4 H9 N O3" 119.119 THR y THREONINE ? "L-peptide linking"
|
| 30 |
+
"C11 H12 N2 O2" 204.225 TRP y TRYPTOPHAN ? "L-peptide linking"
|
| 31 |
+
"C9 H11 N O3" 181.189 TYR y TYROSINE ? "L-peptide linking"
|
| 32 |
+
"C5 H11 N O2" 117.146 VAL y VALINE ? "L-peptide linking"
|
| 33 |
+
#
|
| 34 |
+
_entity.id 1
|
| 35 |
+
_entity.pdbx_description "Protein PrgI"
|
| 36 |
+
_entity.type polymer
|
| 37 |
+
#
|
| 38 |
+
_entity_poly.entity_id 1
|
| 39 |
+
_entity_poly.pdbx_strand_id J
|
| 40 |
+
_entity_poly.type polypeptide(L)
|
| 41 |
+
#
|
| 42 |
+
loop_
|
| 43 |
+
_entity_poly_seq.entity_id
|
| 44 |
+
_entity_poly_seq.hetero
|
| 45 |
+
_entity_poly_seq.mon_id
|
| 46 |
+
_entity_poly_seq.num
|
| 47 |
+
1 n MET 1
|
| 48 |
+
1 n ALA 2
|
| 49 |
+
1 n THR 3
|
| 50 |
+
1 n PRO 4
|
| 51 |
+
1 n TRP 5
|
| 52 |
+
1 n SER 6
|
| 53 |
+
1 n GLY 7
|
| 54 |
+
1 n TYR 8
|
| 55 |
+
1 n LEU 9
|
| 56 |
+
1 n ASP 10
|
| 57 |
+
1 n ASP 11
|
| 58 |
+
1 n VAL 12
|
| 59 |
+
1 n SER 13
|
| 60 |
+
1 n ALA 14
|
| 61 |
+
1 n LYS 15
|
| 62 |
+
1 n PHE 16
|
| 63 |
+
1 n ASP 17
|
| 64 |
+
1 n THR 18
|
| 65 |
+
1 n GLY 19
|
| 66 |
+
1 n VAL 20
|
| 67 |
+
1 n ASP 21
|
| 68 |
+
1 n ASN 22
|
| 69 |
+
1 n LEU 23
|
| 70 |
+
1 n GLN 24
|
| 71 |
+
1 n THR 25
|
| 72 |
+
1 n GLN 26
|
| 73 |
+
1 n VAL 27
|
| 74 |
+
1 n THR 28
|
| 75 |
+
1 n GLU 29
|
| 76 |
+
1 n ALA 30
|
| 77 |
+
1 n LEU 31
|
| 78 |
+
1 n ASP 32
|
| 79 |
+
1 n LYS 33
|
| 80 |
+
1 n LEU 34
|
| 81 |
+
1 n ALA 35
|
| 82 |
+
1 n ALA 36
|
| 83 |
+
1 n LYS 37
|
| 84 |
+
1 n PRO 38
|
| 85 |
+
1 n SER 39
|
| 86 |
+
1 n ASP 40
|
| 87 |
+
1 n PRO 41
|
| 88 |
+
1 n ALA 42
|
| 89 |
+
1 n LEU 43
|
| 90 |
+
1 n LEU 44
|
| 91 |
+
1 n ALA 45
|
| 92 |
+
1 n ALA 46
|
| 93 |
+
1 n TYR 47
|
| 94 |
+
1 n GLN 48
|
| 95 |
+
1 n SER 49
|
| 96 |
+
1 n LYS 50
|
| 97 |
+
1 n LEU 51
|
| 98 |
+
1 n SER 52
|
| 99 |
+
1 n GLU 53
|
| 100 |
+
1 n TYR 54
|
| 101 |
+
1 n ASN 55
|
| 102 |
+
1 n LEU 56
|
| 103 |
+
1 n TYR 57
|
| 104 |
+
1 n ARG 58
|
| 105 |
+
1 n ASN 59
|
| 106 |
+
1 n ALA 60
|
| 107 |
+
1 n GLN 61
|
| 108 |
+
1 n SER 62
|
| 109 |
+
1 n ASN 63
|
| 110 |
+
1 n THR 64
|
| 111 |
+
1 n VAL 65
|
| 112 |
+
1 n LYS 66
|
| 113 |
+
1 n VAL 67
|
| 114 |
+
1 n PHE 68
|
| 115 |
+
1 n LYS 69
|
| 116 |
+
1 n ASP 70
|
| 117 |
+
1 n ILE 71
|
| 118 |
+
1 n ASP 72
|
| 119 |
+
1 n ALA 73
|
| 120 |
+
1 n ALA 74
|
| 121 |
+
1 n ILE 75
|
| 122 |
+
1 n ILE 76
|
| 123 |
+
1 n GLN 77
|
| 124 |
+
1 n ASN 78
|
| 125 |
+
1 n PHE 79
|
| 126 |
+
1 n ARG 80
|
| 127 |
+
#
|
| 128 |
+
_exptl.method "ELECTRON MICROSCOPY"
|
| 129 |
+
#
|
| 130 |
+
_pdbx_audit_revision_history.revision_date 2021-11-10
|
| 131 |
+
#
|
| 132 |
+
_pdbx_database_status.recvd_initial_deposition_date 2021-11-10
|
| 133 |
+
#
|
| 134 |
+
loop_
|
| 135 |
+
_pdbx_poly_seq_scheme.asym_id
|
| 136 |
+
_pdbx_poly_seq_scheme.auth_seq_num
|
| 137 |
+
_pdbx_poly_seq_scheme.entity_id
|
| 138 |
+
_pdbx_poly_seq_scheme.hetero
|
| 139 |
+
_pdbx_poly_seq_scheme.mon_id
|
| 140 |
+
_pdbx_poly_seq_scheme.pdb_ins_code
|
| 141 |
+
_pdbx_poly_seq_scheme.pdb_seq_num
|
| 142 |
+
_pdbx_poly_seq_scheme.pdb_strand_id
|
| 143 |
+
_pdbx_poly_seq_scheme.seq_id
|
| 144 |
+
J ? 1 n MET . 1 J 1
|
| 145 |
+
J ? 1 n ALA . 2 J 2
|
| 146 |
+
J 3 1 n THR . 3 J 3
|
| 147 |
+
J 4 1 n PRO . 4 J 4
|
| 148 |
+
J 5 1 n TRP . 5 J 5
|
| 149 |
+
J 6 1 n SER . 6 J 6
|
| 150 |
+
J 7 1 n GLY . 7 J 7
|
| 151 |
+
J 8 1 n TYR . 8 J 8
|
| 152 |
+
J 9 1 n LEU . 9 J 9
|
| 153 |
+
J 10 1 n ASP . 10 J 10
|
| 154 |
+
J 11 1 n ASP . 11 J 11
|
| 155 |
+
J 12 1 n VAL . 12 J 12
|
| 156 |
+
J 13 1 n SER . 13 J 13
|
| 157 |
+
J 14 1 n ALA . 14 J 14
|
| 158 |
+
J 15 1 n LYS . 15 J 15
|
| 159 |
+
J 16 1 n PHE . 16 J 16
|
| 160 |
+
J 17 1 n ASP . 17 J 17
|
| 161 |
+
J 18 1 n THR . 18 J 18
|
| 162 |
+
J 19 1 n GLY . 19 J 19
|
| 163 |
+
J 20 1 n VAL . 20 J 20
|
| 164 |
+
J 21 1 n ASP . 21 J 21
|
| 165 |
+
J 22 1 n ASN . 22 J 22
|
| 166 |
+
J 23 1 n LEU . 23 J 23
|
| 167 |
+
J 24 1 n GLN . 24 J 24
|
| 168 |
+
J 25 1 n THR . 25 J 25
|
| 169 |
+
J 26 1 n GLN . 26 J 26
|
| 170 |
+
J 27 1 n VAL . 27 J 27
|
| 171 |
+
J 28 1 n THR . 28 J 28
|
| 172 |
+
J 29 1 n GLU . 29 J 29
|
| 173 |
+
J 30 1 n ALA . 30 J 30
|
| 174 |
+
J 31 1 n LEU . 31 J 31
|
| 175 |
+
J 32 1 n ASP . 32 J 32
|
| 176 |
+
J 33 1 n LYS . 33 J 33
|
| 177 |
+
J 34 1 n LEU . 34 J 34
|
| 178 |
+
J 35 1 n ALA . 35 J 35
|
| 179 |
+
J 36 1 n ALA . 36 J 36
|
| 180 |
+
J 37 1 n LYS . 37 J 37
|
| 181 |
+
J 38 1 n PRO . 38 J 38
|
| 182 |
+
J 39 1 n SER . 39 J 39
|
| 183 |
+
J 40 1 n ASP . 40 J 40
|
| 184 |
+
J 41 1 n PRO . 41 J 41
|
| 185 |
+
J 42 1 n ALA . 42 J 42
|
| 186 |
+
J 43 1 n LEU . 43 J 43
|
| 187 |
+
J 44 1 n LEU . 44 J 44
|
| 188 |
+
J 45 1 n ALA . 45 J 45
|
| 189 |
+
J 46 1 n ALA . 46 J 46
|
| 190 |
+
J 47 1 n TYR . 47 J 47
|
| 191 |
+
J 48 1 n GLN . 48 J 48
|
| 192 |
+
J 49 1 n SER . 49 J 49
|
| 193 |
+
J 50 1 n LYS . 50 J 50
|
| 194 |
+
J 51 1 n LEU . 51 J 51
|
| 195 |
+
J 52 1 n SER . 52 J 52
|
| 196 |
+
J 53 1 n GLU . 53 J 53
|
| 197 |
+
J 54 1 n TYR . 54 J 54
|
| 198 |
+
J 55 1 n ASN . 55 J 55
|
| 199 |
+
J 56 1 n LEU . 56 J 56
|
| 200 |
+
J 57 1 n TYR . 57 J 57
|
| 201 |
+
J 58 1 n ARG . 58 J 58
|
| 202 |
+
J 59 1 n ASN . 59 J 59
|
| 203 |
+
J 60 1 n ALA . 60 J 60
|
| 204 |
+
J 61 1 n GLN . 61 J 61
|
| 205 |
+
J 62 1 n SER . 62 J 62
|
| 206 |
+
J 63 1 n ASN . 63 J 63
|
| 207 |
+
J 64 1 n THR . 64 J 64
|
| 208 |
+
J 65 1 n VAL . 65 J 65
|
| 209 |
+
J 66 1 n LYS . 66 J 66
|
| 210 |
+
J 67 1 n VAL . 67 J 67
|
| 211 |
+
J 68 1 n PHE . 68 J 68
|
| 212 |
+
J 69 1 n LYS . 69 J 69
|
| 213 |
+
J 70 1 n ASP . 70 J 70
|
| 214 |
+
J 71 1 n ILE . 71 J 71
|
| 215 |
+
J 72 1 n ASP . 72 J 72
|
| 216 |
+
J 73 1 n ALA . 73 J 73
|
| 217 |
+
J 74 1 n ALA . 74 J 74
|
| 218 |
+
J 75 1 n ILE . 75 J 75
|
| 219 |
+
J 76 1 n ILE . 76 J 76
|
| 220 |
+
J 77 1 n GLN . 77 J 77
|
| 221 |
+
J 78 1 n ASN . 78 J 78
|
| 222 |
+
J 79 1 n PHE . 79 J 79
|
| 223 |
+
J 80 1 n ARG . 80 J 80
|
| 224 |
+
#
|
| 225 |
+
_pdbx_struct_assembly.details author_defined_assembly
|
| 226 |
+
_pdbx_struct_assembly.id 1
|
| 227 |
+
_pdbx_struct_assembly.method_details ?
|
| 228 |
+
_pdbx_struct_assembly.oligomeric_count 24
|
| 229 |
+
_pdbx_struct_assembly.oligomeric_details 24-meric
|
| 230 |
+
#
|
| 231 |
+
_pdbx_struct_assembly_gen.assembly_id 1
|
| 232 |
+
_pdbx_struct_assembly_gen.asym_id_list A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X
|
| 233 |
+
_pdbx_struct_assembly_gen.oper_expression 1
|
| 234 |
+
#
|
| 235 |
+
_pdbx_struct_oper_list.id 1
|
| 236 |
+
_pdbx_struct_oper_list.matrix[1][1] 1.0000000000
|
| 237 |
+
_pdbx_struct_oper_list.matrix[1][2] 0.0000000000
|
| 238 |
+
_pdbx_struct_oper_list.matrix[1][3] 0.0000000000
|
| 239 |
+
_pdbx_struct_oper_list.matrix[2][1] 0.0000000000
|
| 240 |
+
_pdbx_struct_oper_list.matrix[2][2] 1.0000000000
|
| 241 |
+
_pdbx_struct_oper_list.matrix[2][3] 0.0000000000
|
| 242 |
+
_pdbx_struct_oper_list.matrix[3][1] 0.0000000000
|
| 243 |
+
_pdbx_struct_oper_list.matrix[3][2] 0.0000000000
|
| 244 |
+
_pdbx_struct_oper_list.matrix[3][3] 1.0000000000
|
| 245 |
+
_pdbx_struct_oper_list.name 1_555
|
| 246 |
+
_pdbx_struct_oper_list.symmetry_operation ?
|
| 247 |
+
_pdbx_struct_oper_list.type "identity operation"
|
| 248 |
+
_pdbx_struct_oper_list.vector[1] 0.0000000000
|
| 249 |
+
_pdbx_struct_oper_list.vector[2] 0.0000000000
|
| 250 |
+
_pdbx_struct_oper_list.vector[3] 0.0000000000
|
| 251 |
+
#
|
| 252 |
+
_refine.ls_d_res_high 3.90
|
| 253 |
+
#
|
| 254 |
+
_software.classification other
|
| 255 |
+
_software.name "DeepMind Structure Class"
|
| 256 |
+
_software.pdbx_ordinal 1
|
| 257 |
+
_software.version 2.0.0
|
| 258 |
+
#
|
| 259 |
+
_struct_asym.entity_id 1
|
| 260 |
+
_struct_asym.id J
|
| 261 |
+
#
|
| 262 |
+
loop_
|
| 263 |
+
_atom_site.group_PDB
|
| 264 |
+
_atom_site.id
|
| 265 |
+
_atom_site.type_symbol
|
| 266 |
+
_atom_site.label_atom_id
|
| 267 |
+
_atom_site.label_alt_id
|
| 268 |
+
_atom_site.label_comp_id
|
| 269 |
+
_atom_site.label_asym_id
|
| 270 |
+
_atom_site.label_entity_id
|
| 271 |
+
_atom_site.label_seq_id
|
| 272 |
+
_atom_site.pdbx_PDB_ins_code
|
| 273 |
+
_atom_site.Cartn_x
|
| 274 |
+
_atom_site.Cartn_y
|
| 275 |
+
_atom_site.Cartn_z
|
| 276 |
+
_atom_site.occupancy
|
| 277 |
+
_atom_site.B_iso_or_equiv
|
| 278 |
+
_atom_site.auth_seq_id
|
| 279 |
+
_atom_site.auth_asym_id
|
| 280 |
+
_atom_site.pdbx_PDB_model_num
|
| 281 |
+
ATOM 1 N N . THR J 1 3 ? 180.798 156.981 49.506 1.00 100.87 3 J 1
|
| 282 |
+
ATOM 2 C CA . THR J 1 3 ? 180.336 158.053 50.380 1.00 100.87 3 J 1
|
| 283 |
+
ATOM 3 C C . THR J 1 3 ? 178.888 157.811 50.811 1.00 100.87 3 J 1
|
| 284 |
+
ATOM 4 O O . THR J 1 3 ? 178.076 157.312 50.030 1.00 100.87 3 J 1
|
| 285 |
+
ATOM 5 C CB . THR J 1 3 ? 180.468 159.436 49.691 1.00 100.87 3 J 1
|
| 286 |
+
ATOM 6 O OG1 . THR J 1 3 ? 180.169 160.478 50.627 1.00 100.87 3 J 1
|
| 287 |
+
ATOM 7 C CG2 . THR J 1 3 ? 179.541 159.546 48.488 1.00 100.87 3 J 1
|
| 288 |
+
ATOM 8 N N . PRO J 1 4 ? 178.569 158.139 52.065 1.00 96.05 4 J 1
|
| 289 |
+
ATOM 9 C CA . PRO J 1 4 ? 177.201 157.918 52.554 1.00 96.05 4 J 1
|
| 290 |
+
ATOM 10 C C . PRO J 1 4 ? 176.203 158.873 51.924 1.00 96.05 4 J 1
|
| 291 |
+
ATOM 11 O O . PRO J 1 4 ? 176.293 160.090 52.112 1.00 96.05 4 J 1
|
| 292 |
+
ATOM 12 C CB . PRO J 1 4 ? 177.326 158.152 54.065 1.00 96.05 4 J 1
|
| 293 |
+
ATOM 13 C CG . PRO J 1 4 ? 178.504 159.047 54.212 1.00 96.05 4 J 1
|
| 294 |
+
ATOM 14 C CD . PRO J 1 4 ? 179.457 158.664 53.117 1.00 96.05 4 J 1
|
| 295 |
+
ATOM 15 N N . TRP J 1 5 ? 175.251 158.334 51.169 1.00 82.05 5 J 1
|
| 296 |
+
ATOM 16 C CA . TRP J 1 5 ? 174.242 159.172 50.543 1.00 82.05 5 J 1
|
| 297 |
+
ATOM 17 C C . TRP J 1 5 ? 173.275 159.710 51.591 1.00 82.05 5 J 1
|
| 298 |
+
ATOM 18 O O . TRP J 1 5 ? 173.068 159.105 52.647 1.00 82.05 5 J 1
|
| 299 |
+
ATOM 19 C CB . TRP J 1 5 ? 173.467 158.390 49.486 1.00 82.05 5 J 1
|
| 300 |
+
ATOM 20 C CG . TRP J 1 5 ? 172.575 159.261 48.675 1.00 82.05 5 J 1
|
| 301 |
+
ATOM 21 C CD1 . TRP J 1 5 ? 172.953 160.130 47.697 1.00 82.05 5 J 1
|
| 302 |
+
ATOM 22 C CD2 . TRP J 1 5 ? 171.158 159.402 48.811 1.00 82.05 5 J 1
|
| 303 |
+
ATOM 23 N NE1 . TRP J 1 5 ? 171.856 160.778 47.189 1.00 82.05 5 J 1
|
| 304 |
+
ATOM 24 C CE2 . TRP J 1 5 ? 170.741 160.351 47.859 1.00 82.05 5 J 1
|
| 305 |
+
ATOM 25 C CE3 . TRP J 1 5 ? 170.199 158.807 49.634 1.00 82.05 5 J 1
|
| 306 |
+
ATOM 26 C CZ2 . TRP J 1 5 ? 169.408 160.720 47.709 1.00 82.05 5 J 1
|
| 307 |
+
ATOM 27 C CZ3 . TRP J 1 5 ? 168.877 159.176 49.482 1.00 82.05 5 J 1
|
| 308 |
+
ATOM 28 C CH2 . TRP J 1 5 ? 168.493 160.120 48.527 1.00 82.05 5 J 1
|
| 309 |
+
ATOM 29 N N . SER J 1 6 ? 172.676 160.860 51.291 1.00 78.94 6 J 1
|
| 310 |
+
ATOM 30 C CA . SER J 1 6 ? 171.730 161.484 52.213 1.00 78.94 6 J 1
|
| 311 |
+
ATOM 31 C C . SER J 1 6 ? 170.799 162.391 51.422 1.00 78.94 6 J 1
|
| 312 |
+
ATOM 32 O O . SER J 1 6 ? 171.235 163.417 50.892 1.00 78.94 6 J 1
|
| 313 |
+
ATOM 33 C CB . SER J 1 6 ? 172.462 162.265 53.300 1.00 78.94 6 J 1
|
| 314 |
+
ATOM 34 O OG . SER J 1 6 ? 173.149 161.389 54.176 1.00 78.94 6 J 1
|
| 315 |
+
ATOM 35 N N . GLY J 1 7 ? 169.526 162.014 51.347 1.00 80.09 7 J 1
|
| 316 |
+
ATOM 36 C CA . GLY J 1 7 ? 168.512 162.855 50.750 1.00 80.09 7 J 1
|
| 317 |
+
ATOM 37 C C . GLY J 1 7 ? 168.082 163.958 51.698 1.00 80.09 7 J 1
|
| 318 |
+
ATOM 38 O O . GLY J 1 7 ? 168.539 164.059 52.838 1.00 80.09 7 J 1
|
| 319 |
+
ATOM 39 N N . TYR J 1 8 ? 167.174 164.804 51.207 1.00 78.37 8 J 1
|
| 320 |
+
ATOM 40 C CA . TYR J 1 8 ? 166.760 165.964 51.991 1.00 78.37 8 J 1
|
| 321 |
+
ATOM 41 C C . TYR J 1 8 ? 166.084 165.523 53.284 1.00 78.37 8 J 1
|
| 322 |
+
ATOM 42 O O . TYR J 1 8 ? 166.332 166.093 54.351 1.00 78.37 8 J 1
|
| 323 |
+
ATOM 43 C CB . TYR J 1 8 ? 165.830 166.858 51.167 1.00 78.37 8 J 1
|
| 324 |
+
ATOM 44 C CG . TYR J 1 8 ? 165.412 168.151 51.846 1.00 78.37 8 J 1
|
| 325 |
+
ATOM 45 C CD1 . TYR J 1 8 ? 164.409 168.939 51.311 1.00 78.37 8 J 1
|
| 326 |
+
ATOM 46 C CD2 . TYR J 1 8 ? 166.073 168.622 52.974 1.00 78.37 8 J 1
|
| 327 |
+
ATOM 47 C CE1 . TYR J 1 8 ? 164.036 170.122 51.913 1.00 78.37 8 J 1
|
| 328 |
+
ATOM 48 C CE2 . TYR J 1 8 ? 165.705 169.801 53.581 1.00 78.37 8 J 1
|
| 329 |
+
ATOM 49 C CZ . TYR J 1 8 ? 164.688 170.550 53.044 1.00 78.37 8 J 1
|
| 330 |
+
ATOM 50 O OH . TYR J 1 8 ? 164.318 171.735 53.638 1.00 78.37 8 J 1
|
| 331 |
+
ATOM 51 N N . LEU J 1 9 ? 165.226 164.506 53.213 1.00 73.64 9 J 1
|
| 332 |
+
ATOM 52 C CA . LEU J 1 9 ? 164.645 163.967 54.439 1.00 73.64 9 J 1
|
| 333 |
+
ATOM 53 C C . LEU J 1 9 ? 165.730 163.390 55.340 1.00 73.64 9 J 1
|
| 334 |
+
ATOM 54 O O . LEU J 1 9 ? 165.719 163.604 56.560 1.00 73.64 9 J 1
|
| 335 |
+
ATOM 55 C CB . LEU J 1 9 ? 163.595 162.906 54.109 1.00 73.64 9 J 1
|
| 336 |
+
ATOM 56 C CG . LEU J 1 9 ? 162.192 163.335 53.661 1.00 73.64 9 J 1
|
| 337 |
+
ATOM 57 C CD1 . LEU J 1 9 ? 162.211 164.303 52.488 1.00 73.64 9 J 1
|
| 338 |
+
ATOM 58 C CD2 . LEU J 1 9 ? 161.355 162.112 53.321 1.00 73.64 9 J 1
|
| 339 |
+
ATOM 59 N N . ASP J 1 10 ? 166.683 162.668 54.750 1.00 75.23 10 J 1
|
| 340 |
+
ATOM 60 C CA . ASP J 1 10 ? 167.828 162.189 55.511 1.00 75.23 10 J 1
|
| 341 |
+
ATOM 61 C C . ASP J 1 10 ? 168.631 163.360 56.062 1.00 75.23 10 J 1
|
| 342 |
+
ATOM 62 O O . ASP J 1 10 ? 169.140 163.297 57.186 1.00 75.23 10 J 1
|
| 343 |
+
ATOM 63 C CB . ASP J 1 10 ? 168.695 161.293 54.624 1.00 75.23 10 J 1
|
| 344 |
+
ATOM 64 C CG . ASP J 1 10 ? 169.793 160.577 55.393 1.00 75.23 10 J 1
|
| 345 |
+
ATOM 65 O OD1 . ASP J 1 10 ? 169.921 160.785 56.617 1.00 75.23 10 J 1
|
| 346 |
+
ATOM 66 O OD2 . ASP J 1 10 ? 170.537 159.796 54.764 1.00 75.23 10 J 1
|
| 347 |
+
ATOM 67 N N . ASP J 1 11 ? 168.742 164.442 55.289 1.00 76.21 11 J 1
|
| 348 |
+
ATOM 68 C CA . ASP J 1 11 ? 169.449 165.624 55.770 1.00 76.21 11 J 1
|
| 349 |
+
ATOM 69 C C . ASP J 1 11 ? 168.755 166.229 56.984 1.00 76.21 11 J 1
|
| 350 |
+
ATOM 70 O O . ASP J 1 11 ? 169.416 166.658 57.932 1.00 76.21 11 J 1
|
| 351 |
+
ATOM 71 C CB . ASP J 1 11 ? 169.573 166.658 54.651 1.00 76.21 11 J 1
|
| 352 |
+
ATOM 72 C CG . ASP J 1 11 ? 170.510 166.210 53.546 1.00 76.21 11 J 1
|
| 353 |
+
ATOM 73 O OD1 . ASP J 1 11 ? 171.452 165.444 53.836 1.00 76.21 11 J 1
|
| 354 |
+
ATOM 74 O OD2 . ASP J 1 11 ? 170.303 166.623 52.386 1.00 76.21 11 J 1
|
| 355 |
+
ATOM 75 N N . VAL J 1 12 ? 167.423 166.274 56.973 1.00 71.19 12 J 1
|
| 356 |
+
ATOM 76 C CA . VAL J 1 12 ? 166.679 166.814 58.107 1.00 71.19 12 J 1
|
| 357 |
+
ATOM 77 C C . VAL J 1 12 ? 166.846 165.921 59.330 1.00 71.19 12 J 1
|
| 358 |
+
ATOM 78 O O . VAL J 1 12 ? 167.032 166.405 60.457 1.00 71.19 12 J 1
|
| 359 |
+
ATOM 79 C CB . VAL J 1 12 ? 165.197 166.989 57.729 1.00 71.19 12 J 1
|
| 360 |
+
ATOM 80 C CG1 . VAL J 1 12 ? 164.358 167.240 58.967 1.00 71.19 12 J 1
|
| 361 |
+
ATOM 81 C CG2 . VAL J 1 12 ? 165.039 168.124 56.733 1.00 71.19 12 J 1
|
| 362 |
+
ATOM 82 N N . SER J 1 13 ? 166.779 164.604 59.130 1.00 71.31 13 J 1
|
| 363 |
+
ATOM 83 C CA . SER J 1 13 ? 167.004 163.691 60.244 1.00 71.31 13 J 1
|
| 364 |
+
ATOM 84 C C . SER J 1 13 ? 168.397 163.882 60.831 1.00 71.31 13 J 1
|
| 365 |
+
ATOM 85 O O . SER J 1 13 ? 168.555 163.965 62.054 1.00 71.31 13 J 1
|
| 366 |
+
ATOM 86 C CB . SER J 1 13 ? 166.801 162.246 59.794 1.00 71.31 13 J 1
|
| 367 |
+
ATOM 87 O OG . SER J 1 13 ? 165.459 162.023 59.402 1.00 71.31 13 J 1
|
| 368 |
+
ATOM 88 N N . ALA J 1 14 ? 169.413 163.985 59.972 1.00 73.94 14 J 1
|
| 369 |
+
ATOM 89 C CA . ALA J 1 14 ? 170.773 164.209 60.451 1.00 73.94 14 J 1
|
| 370 |
+
ATOM 90 C C . ALA J 1 14 ? 170.904 165.566 61.130 1.00 73.94 14 J 1
|
| 371 |
+
ATOM 91 O O . ALA J 1 14 ? 171.700 165.728 62.061 1.00 73.94 14 J 1
|
| 372 |
+
ATOM 92 C CB . ALA J 1 14 ? 171.765 164.087 59.295 1.00 73.94 14 J 1
|
| 373 |
+
ATOM 93 N N . LYS J 1 15 ? 170.140 166.557 60.668 1.00 71.21 15 J 1
|
| 374 |
+
ATOM 94 C CA . LYS J 1 15 ? 170.140 167.860 61.321 1.00 71.21 15 J 1
|
| 375 |
+
ATOM 95 C C . LYS J 1 15 ? 169.612 167.753 62.742 1.00 71.21 15 J 1
|
| 376 |
+
ATOM 96 O O . LYS J 1 15 ? 170.146 168.383 63.660 1.00 71.21 15 J 1
|
| 377 |
+
ATOM 97 C CB . LYS J 1 15 ? 169.311 168.855 60.511 1.00 71.21 15 J 1
|
| 378 |
+
ATOM 98 C CG . LYS J 1 15 ? 170.142 169.773 59.635 1.00 71.21 15 J 1
|
| 379 |
+
ATOM 99 C CD . LYS J 1 15 ? 169.313 170.920 59.089 1.00 71.21 15 J 1
|
| 380 |
+
ATOM 100 C CE . LYS J 1 15 ? 170.176 171.888 58.300 1.00 71.21 15 J 1
|
| 381 |
+
ATOM 101 N NZ . LYS J 1 15 ? 169.369 172.970 57.676 1.00 71.21 15 J 1
|
| 382 |
+
ATOM 102 N N . PHE J 1 16 ? 168.559 166.963 62.943 1.00 68.61 16 J 1
|
| 383 |
+
ATOM 103 C CA . PHE J 1 16 ? 168.102 166.713 64.308 1.00 68.61 16 J 1
|
| 384 |
+
ATOM 104 C C . PHE J 1 16 ? 169.128 165.927 65.120 1.00 68.61 16 J 1
|
| 385 |
+
ATOM 105 O O . PHE J 1 16 ? 169.342 166.226 66.300 1.00 68.61 16 J 1
|
| 386 |
+
ATOM 106 C CB . PHE J 1 16 ? 166.749 166.005 64.309 1.00 68.61 16 J 1
|
| 387 |
+
ATOM 107 C CG . PHE J 1 16 ? 165.587 166.929 64.088 1.00 68.61 16 J 1
|
| 388 |
+
ATOM 108 C CD1 . PHE J 1 16 ? 165.736 168.293 64.256 1.00 68.61 16 J 1
|
| 389 |
+
ATOM 109 C CD2 . PHE J 1 16 ? 164.345 166.437 63.736 1.00 68.61 16 J 1
|
| 390 |
+
ATOM 110 C CE1 . PHE J 1 16 ? 164.670 169.147 64.068 1.00 68.61 16 J 1
|
| 391 |
+
ATOM 111 C CE2 . PHE J 1 16 ? 163.277 167.286 63.544 1.00 68.61 16 J 1
|
| 392 |
+
ATOM 112 C CZ . PHE J 1 16 ? 163.439 168.643 63.710 1.00 68.61 16 J 1
|
| 393 |
+
ATOM 113 N N . ASP J 1 17 ? 169.768 164.918 64.521 1.00 77.06 17 J 1
|
| 394 |
+
ATOM 114 C CA . ASP J 1 17 ? 170.752 164.149 65.286 1.00 77.06 17 J 1
|
| 395 |
+
ATOM 115 C C . ASP J 1 17 ? 171.927 165.017 65.719 1.00 77.06 17 J 1
|
| 396 |
+
ATOM 116 O O . ASP J 1 17 ? 172.413 164.888 66.848 1.00 77.06 17 J 1
|
| 397 |
+
ATOM 117 C CB . ASP J 1 17 ? 171.254 162.929 64.509 1.00 77.06 17 J 1
|
| 398 |
+
ATOM 118 C CG . ASP J 1 17 ? 170.136 162.119 63.888 1.00 77.06 17 J 1
|
| 399 |
+
ATOM 119 O OD1 . ASP J 1 17 ? 170.103 162.001 62.647 1.00 77.06 17 J 1
|
| 400 |
+
ATOM 120 O OD2 . ASP J 1 17 ? 169.286 161.602 64.642 1.00 77.06 17 J 1
|
| 401 |
+
ATOM 121 N N . THR J 1 18 ? 172.399 165.901 64.845 1.00 76.90 18 J 1
|
| 402 |
+
ATOM 122 C CA . THR J 1 18 ? 173.485 166.801 65.205 1.00 76.90 18 J 1
|
| 403 |
+
ATOM 123 C C . THR J 1 18 ? 173.016 167.991 66.028 1.00 76.90 18 J 1
|
| 404 |
+
ATOM 124 O O . THR J 1 18 ? 173.851 168.678 66.626 1.00 76.90 18 J 1
|
| 405 |
+
ATOM 125 C CB . THR J 1 18 ? 174.203 167.303 63.949 1.00 76.90 18 J 1
|
| 406 |
+
ATOM 126 O OG1 . THR J 1 18 ? 175.476 167.849 64.314 1.00 76.90 18 J 1
|
| 407 |
+
ATOM 127 C CG2 . THR J 1 18 ? 173.381 168.373 63.253 1.00 76.90 18 J 1
|
| 408 |
+
ATOM 128 N N . GLY J 1 19 ? 171.709 168.255 66.067 1.00 78.19 19 J 1
|
| 409 |
+
ATOM 129 C CA . GLY J 1 19 ? 171.207 169.320 66.916 1.00 78.19 19 J 1
|
| 410 |
+
ATOM 130 C C . GLY J 1 19 ? 171.381 169.012 68.389 1.00 78.19 19 J 1
|
| 411 |
+
ATOM 131 O O . GLY J 1 19 ? 171.777 169.879 69.172 1.00 78.19 19 J 1
|
| 412 |
+
ATOM 132 N N . VAL J 1 20 ? 171.089 167.780 68.785 1.00 76.12 20 J 1
|
| 413 |
+
ATOM 133 C CA . VAL J 1 20 ? 171.317 167.329 70.150 1.00 76.12 20 J 1
|
| 414 |
+
ATOM 134 C C . VAL J 1 20 ? 172.694 166.684 70.220 1.00 76.12 20 J 1
|
| 415 |
+
ATOM 135 O O . VAL J 1 20 ? 173.054 165.862 69.368 1.00 76.12 20 J 1
|
| 416 |
+
ATOM 136 C CB . VAL J 1 20 ? 170.212 166.362 70.606 1.00 76.12 20 J 1
|
| 417 |
+
ATOM 137 C CG1 . VAL J 1 20 ? 168.869 167.069 70.596 1.00 76.12 20 J 1
|
| 418 |
+
ATOM 138 C CG2 . VAL J 1 20 ? 170.158 165.132 69.713 1.00 76.12 20 J 1
|
| 419 |
+
ATOM 139 N N . ASP J 1 21 ? 173.487 167.090 71.210 1.00 78.41 21 J 1
|
| 420 |
+
ATOM 140 C CA . ASP J 1 21 ? 174.863 166.617 71.290 1.00 78.41 21 J 1
|
| 421 |
+
ATOM 141 C C . ASP J 1 21 ? 174.916 165.113 71.524 1.00 78.41 21 J 1
|
| 422 |
+
ATOM 142 O O . ASP J 1 21 ? 175.347 164.349 70.653 1.00 78.41 21 J 1
|
| 423 |
+
ATOM 143 C CB . ASP J 1 21 ? 175.608 167.363 72.396 1.00 78.41 21 J 1
|
| 424 |
+
ATOM 144 C CG . ASP J 1 21 ? 175.835 168.824 72.061 1.00 78.41 21 J 1
|
| 425 |
+
ATOM 145 O OD1 . ASP J 1 21 ? 175.946 169.149 70.861 1.00 78.41 21 J 1
|
| 426 |
+
ATOM 146 O OD2 . ASP J 1 21 ? 175.903 169.647 72.998 1.00 78.41 21 J 1
|
| 427 |
+
ATOM 147 N N . ASN J 1 22 ? 174.471 164.668 72.693 1.00 74.91 22 J 1
|
| 428 |
+
ATOM 148 C CA . ASN J 1 22 ? 174.565 163.267 73.084 1.00 74.91 22 J 1
|
| 429 |
+
ATOM 149 C C . ASN J 1 22 ? 173.277 162.819 73.765 1.00 74.91 22 J 1
|
| 430 |
+
ATOM 150 O O . ASN J 1 22 ? 173.294 162.151 74.799 1.00 74.91 22 J 1
|
| 431 |
+
ATOM 151 C CB . ASN J 1 22 ? 175.777 163.050 73.987 1.00 74.91 22 J 1
|
| 432 |
+
ATOM 152 C CG . ASN J 1 22 ? 175.825 164.032 75.138 1.00 74.91 22 J 1
|
| 433 |
+
ATOM 153 O OD1 . ASN J 1 22 ? 174.925 164.855 75.304 1.00 74.91 22 J 1
|
| 434 |
+
ATOM 154 N ND2 . ASN J 1 22 ? 176.881 163.956 75.938 1.00 74.91 22 J 1
|
| 435 |
+
ATOM 155 N N . LEU J 1 23 ? 172.134 163.193 73.182 1.00 72.21 23 J 1
|
| 436 |
+
ATOM 156 C CA . LEU J 1 23 ? 170.852 162.915 73.824 1.00 72.21 23 J 1
|
| 437 |
+
ATOM 157 C C . LEU J 1 23 ? 170.648 161.425 74.053 1.00 72.21 23 J 1
|
| 438 |
+
ATOM 158 O O . LEU J 1 23 ? 170.248 161.010 75.146 1.00 72.21 23 J 1
|
| 439 |
+
ATOM 159 C CB . LEU J 1 23 ? 169.708 163.483 72.989 1.00 72.21 23 J 1
|
| 440 |
+
ATOM 160 C CG . LEU J 1 23 ? 168.328 163.271 73.612 1.00 72.21 23 J 1
|
| 441 |
+
ATOM 161 C CD1 . LEU J 1 23 ? 168.229 163.983 74.946 1.00 72.21 23 J 1
|
| 442 |
+
ATOM 162 C CD2 . LEU J 1 23 ? 167.237 163.743 72.669 1.00 72.21 23 J 1
|
| 443 |
+
ATOM 163 N N . GLN J 1 24 ? 170.920 160.601 73.039 1.00 70.63 24 J 1
|
| 444 |
+
ATOM 164 C CA . GLN J 1 24 ? 170.840 159.157 73.230 1.00 70.63 24 J 1
|
| 445 |
+
ATOM 165 C C . GLN J 1 24 ? 171.802 158.707 74.320 1.00 70.63 24 J 1
|
| 446 |
+
ATOM 166 O O . GLN J 1 24 ? 171.425 157.974 75.242 1.00 70.63 24 J 1
|
| 447 |
+
ATOM 167 C CB . GLN J 1 24 ? 171.143 158.435 71.917 1.00 70.63 24 J 1
|
| 448 |
+
ATOM 168 C CG . GLN J 1 24 ? 170.834 156.949 71.947 1.00 70.63 24 J 1
|
| 449 |
+
ATOM 169 C CD . GLN J 1 24 ? 169.405 156.644 71.556 1.00 70.63 24 J 1
|
| 450 |
+
ATOM 170 O OE1 . GLN J 1 24 ? 168.697 157.505 71.042 1.00 70.63 24 J 1
|
| 451 |
+
ATOM 171 N NE2 . GLN J 1 24 ? 168.972 155.412 71.801 1.00 70.63 24 J 1
|
| 452 |
+
ATOM 172 N N . THR J 1 25 ? 173.052 159.167 74.242 1.00 72.05 25 J 1
|
| 453 |
+
ATOM 173 C CA . THR J 1 25 ? 174.029 158.829 75.267 1.00 72.05 25 J 1
|
| 454 |
+
ATOM 174 C C . THR J 1 25 ? 173.628 159.382 76.627 1.00 72.05 25 J 1
|
| 455 |
+
ATOM 175 O O . THR J 1 25 ? 173.752 158.681 77.636 1.00 72.05 25 J 1
|
| 456 |
+
ATOM 176 C CB . THR J 1 25 ? 175.407 159.349 74.865 1.00 72.05 25 J 1
|
| 457 |
+
ATOM 177 O OG1 . THR J 1 25 ? 175.777 158.785 73.601 1.00 72.05 25 J 1
|
| 458 |
+
ATOM 178 C CG2 . THR J 1 25 ? 176.447 158.961 75.898 1.00 72.05 25 J 1
|
| 459 |
+
ATOM 179 N N . GLN J 1 26 ? 173.147 160.627 76.676 1.00 73.20 26 J 1
|
| 460 |
+
ATOM 180 C CA . GLN J 1 26 ? 172.756 161.219 77.951 1.00 73.20 26 J 1
|
| 461 |
+
ATOM 181 C C . GLN J 1 26 ? 171.656 160.400 78.610 1.00 73.20 26 J 1
|
| 462 |
+
ATOM 182 O O . GLN J 1 26 ? 171.709 160.118 79.814 1.00 73.20 26 J 1
|
| 463 |
+
ATOM 183 C CB . GLN J 1 26 ? 172.301 162.663 77.739 1.00 73.20 26 J 1
|
| 464 |
+
ATOM 184 C CG . GLN J 1 26 ? 173.397 163.693 77.939 1.00 73.20 26 J 1
|
| 465 |
+
ATOM 185 C CD . GLN J 1 26 ? 172.920 165.105 77.674 1.00 73.20 26 J 1
|
| 466 |
+
ATOM 186 O OE1 . GLN J 1 26 ? 171.782 165.454 77.979 1.00 73.20 26 J 1
|
| 467 |
+
ATOM 187 N NE2 . GLN J 1 26 ? 173.791 165.926 77.101 1.00 73.20 26 J 1
|
| 468 |
+
ATOM 188 N N . VAL J 1 27 ? 170.660 159.989 77.824 1.00 70.38 27 J 1
|
| 469 |
+
ATOM 189 C CA . VAL J 1 27 ? 169.615 159.113 78.339 1.00 70.38 27 J 1
|
| 470 |
+
ATOM 190 C C . VAL J 1 27 ? 170.211 157.789 78.796 1.00 70.38 27 J 1
|
| 471 |
+
ATOM 191 O O . VAL J 1 27 ? 169.787 157.217 79.808 1.00 70.38 27 J 1
|
| 472 |
+
ATOM 192 C CB . VAL J 1 27 ? 168.521 158.911 77.274 1.00 70.38 27 J 1
|
| 473 |
+
ATOM 193 C CG1 . VAL J 1 27 ? 167.570 157.803 77.685 1.00 70.38 27 J 1
|
| 474 |
+
ATOM 194 C CG2 . VAL J 1 27 ? 167.761 160.204 77.059 1.00 70.38 27 J 1
|
| 475 |
+
ATOM 195 N N . THR J 1 28 ? 171.208 157.285 78.067 1.00 66.97 28 J 1
|
| 476 |
+
ATOM 196 C CA . THR J 1 28 ? 171.814 156.011 78.437 1.00 66.97 28 J 1
|
| 477 |
+
ATOM 197 C C . THR J 1 28 ? 172.453 156.080 79.821 1.00 66.97 28 J 1
|
| 478 |
+
ATOM 198 O O . THR J 1 28 ? 172.163 155.246 80.688 1.00 66.97 28 J 1
|
| 479 |
+
ATOM 199 C CB . THR J 1 28 ? 172.841 155.591 77.388 1.00 66.97 28 J 1
|
| 480 |
+
ATOM 200 O OG1 . THR J 1 28 ? 172.192 155.449 76.118 1.00 66.97 28 J 1
|
| 481 |
+
ATOM 201 C CG2 . THR J 1 28 ? 173.475 154.265 77.774 1.00 66.97 28 J 1
|
| 482 |
+
ATOM 202 N N . GLU J 1 29 ? 173.322 157.072 80.055 1.00 72.66 29 J 1
|
| 483 |
+
ATOM 203 C CA . GLU J 1 29 ? 173.906 157.156 81.396 1.00 72.66 29 J 1
|
| 484 |
+
ATOM 204 C C . GLU J 1 29 ? 172.874 157.531 82.451 1.00 72.66 29 J 1
|
| 485 |
+
ATOM 205 O O . GLU J 1 29 ? 172.996 157.088 83.594 1.00 72.66 29 J 1
|
| 486 |
+
ATOM 206 C CB . GLU J 1 29 ? 175.107 158.111 81.526 1.00 72.66 29 J 1
|
| 487 |
+
ATOM 207 C CG . GLU J 1 29 ? 176.428 157.677 80.874 1.00 72.66 29 J 1
|
| 488 |
+
ATOM 208 C CD . GLU J 1 29 ? 176.594 158.116 79.452 1.00 72.66 29 J 1
|
| 489 |
+
ATOM 209 O OE1 . GLU J 1 29 ? 175.740 158.874 78.981 1.00 72.66 29 J 1
|
| 490 |
+
ATOM 210 O OE2 . GLU J 1 29 ? 177.582 157.707 78.806 1.00 72.66 29 J 1
|
| 491 |
+
ATOM 211 N N . ALA J 1 30 ? 171.858 158.331 82.113 1.00 71.55 30 J 1
|
| 492 |
+
ATOM 212 C CA . ALA J 1 30 ? 170.840 158.641 83.113 1.00 71.55 30 J 1
|
| 493 |
+
ATOM 213 C C . ALA J 1 30 ? 170.124 157.377 83.571 1.00 71.55 30 J 1
|
| 494 |
+
ATOM 214 O O . ALA J 1 30 ? 169.974 157.134 84.776 1.00 71.55 30 J 1
|
| 495 |
+
ATOM 215 C CB . ALA J 1 30 ? 169.842 159.654 82.555 1.00 71.55 30 J 1
|
| 496 |
+
ATOM 216 N N . LEU J 1 31 ? 169.710 156.541 82.619 1.00 67.57 31 J 1
|
| 497 |
+
ATOM 217 C CA . LEU J 1 31 ? 169.026 155.299 82.949 1.00 67.57 31 J 1
|
| 498 |
+
ATOM 218 C C . LEU J 1 31 ? 169.947 154.332 83.681 1.00 67.57 31 J 1
|
| 499 |
+
ATOM 219 O O . LEU J 1 31 ? 169.513 153.645 84.613 1.00 67.57 31 J 1
|
| 500 |
+
ATOM 220 C CB . LEU J 1 31 ? 168.470 154.664 81.675 1.00 67.57 31 J 1
|
| 501 |
+
ATOM 221 C CG . LEU J 1 31 ? 167.565 153.444 81.827 1.00 67.57 31 J 1
|
| 502 |
+
ATOM 222 C CD1 . LEU J 1 31 ? 166.434 153.521 80.822 1.00 67.57 31 J 1
|
| 503 |
+
ATOM 223 C CD2 . LEU J 1 31 ? 168.355 152.161 81.641 1.00 67.57 31 J 1
|
| 504 |
+
ATOM 224 N N . ASP J 1 32 ? 171.217 154.256 83.275 1.00 72.67 32 J 1
|
| 505 |
+
ATOM 225 C CA . ASP J 1 32 ? 172.149 153.367 83.960 1.00 72.67 32 J 1
|
| 506 |
+
ATOM 226 C C . ASP J 1 32 ? 172.379 153.821 85.398 1.00 72.67 32 J 1
|
| 507 |
+
ATOM 227 O O . ASP J 1 32 ? 172.414 152.997 86.319 1.00 72.67 32 J 1
|
| 508 |
+
ATOM 228 C CB . ASP J 1 32 ? 173.467 153.305 83.188 1.00 72.67 32 J 1
|
| 509 |
+
ATOM 229 C CG . ASP J 1 32 ? 174.413 152.240 83.718 1.00 72.67 32 J 1
|
| 510 |
+
ATOM 230 O OD1 . ASP J 1 32 ? 174.073 151.558 84.706 1.00 72.67 32 J 1
|
| 511 |
+
ATOM 231 O OD2 . ASP J 1 32 ? 175.507 152.083 83.137 1.00 72.67 32 J 1
|
| 512 |
+
ATOM 232 N N . LYS J 1 33 ? 172.532 155.130 85.610 1.00 71.55 33 J 1
|
| 513 |
+
ATOM 233 C CA . LYS J 1 33 ? 172.715 155.655 86.958 1.00 71.55 33 J 1
|
| 514 |
+
ATOM 234 C C . LYS J 1 33 ? 171.496 155.382 87.824 1.00 71.55 33 J 1
|
| 515 |
+
ATOM 235 O O . LYS J 1 33 ? 171.628 155.006 88.994 1.00 71.55 33 J 1
|
| 516 |
+
ATOM 236 C CB . LYS J 1 33 ? 173.001 157.155 86.900 1.00 71.55 33 J 1
|
| 517 |
+
ATOM 237 C CG . LYS J 1 33 ? 174.385 157.517 86.392 1.00 71.55 33 J 1
|
| 518 |
+
ATOM 238 C CD . LYS J 1 33 ? 174.482 159.007 86.104 1.00 71.55 33 J 1
|
| 519 |
+
ATOM 239 C CE . LYS J 1 33 ? 174.396 159.829 87.379 1.00 71.55 33 J 1
|
| 520 |
+
ATOM 240 N NZ . LYS J 1 33 ? 174.607 161.279 87.119 1.00 71.55 33 J 1
|
| 521 |
+
ATOM 241 N N . LEU J 1 34 ? 170.296 155.566 87.269 1.00 70.34 34 J 1
|
| 522 |
+
ATOM 242 C CA . LEU J 1 34 ? 169.095 155.291 88.045 1.00 70.34 34 J 1
|
| 523 |
+
ATOM 243 C C . LEU J 1 34 ? 168.944 153.807 88.358 1.00 70.34 34 J 1
|
| 524 |
+
ATOM 244 O O . LEU J 1 34 ? 168.263 153.458 89.327 1.00 70.34 34 J 1
|
| 525 |
+
ATOM 245 C CB . LEU J 1 34 ? 167.865 155.824 87.305 1.00 70.34 34 J 1
|
| 526 |
+
ATOM 246 C CG . LEU J 1 34 ? 166.493 155.819 87.987 1.00 70.34 34 J 1
|
| 527 |
+
ATOM 247 C CD1 . LEU J 1 34 ? 165.645 156.923 87.403 1.00 70.34 34 J 1
|
| 528 |
+
ATOM 248 C CD2 . LEU J 1 34 ? 165.773 154.496 87.808 1.00 70.34 34 J 1
|
| 529 |
+
ATOM 249 N N . ALA J 1 35 ? 169.587 152.930 87.582 1.00 66.69 35 J 1
|
| 530 |
+
ATOM 250 C CA . ALA J 1 35 ? 169.434 151.494 87.785 1.00 66.69 35 J 1
|
| 531 |
+
ATOM 251 C C . ALA J 1 35 ? 169.942 151.034 89.144 1.00 66.69 35 J 1
|
| 532 |
+
ATOM 252 O O . ALA J 1 35 ? 169.492 149.995 89.640 1.00 66.69 35 J 1
|
| 533 |
+
ATOM 253 C CB . ALA J 1 35 ? 170.153 150.726 86.678 1.00 66.69 35 J 1
|
| 534 |
+
ATOM 254 N N . ALA J 1 36 ? 170.865 151.775 89.759 1.00 67.09 36 J 1
|
| 535 |
+
ATOM 255 C CA . ALA J 1 36 ? 171.402 151.403 91.059 1.00 67.09 36 J 1
|
| 536 |
+
ATOM 256 C C . ALA J 1 36 ? 171.016 152.357 92.179 1.00 67.09 36 J 1
|
| 537 |
+
ATOM 257 O O . ALA J 1 36 ? 171.066 151.959 93.347 1.00 67.09 36 J 1
|
| 538 |
+
ATOM 258 C CB . ALA J 1 36 ? 172.933 151.307 90.996 1.00 67.09 36 J 1
|
| 539 |
+
ATOM 259 N N . LYS J 1 37 ? 170.632 153.590 91.860 1.00 66.94 37 J 1
|
| 540 |
+
ATOM 260 C CA . LYS J 1 37 ? 170.209 154.579 92.850 1.00 66.94 37 J 1
|
| 541 |
+
ATOM 261 C C . LYS J 1 37 ? 168.843 155.099 92.431 1.00 66.94 37 J 1
|
| 542 |
+
ATOM 262 O O . LYS J 1 37 ? 168.736 156.111 91.726 1.00 66.94 37 J 1
|
| 543 |
+
ATOM 263 C CB . LYS J 1 37 ? 171.229 155.709 92.979 1.00 66.94 37 J 1
|
| 544 |
+
ATOM 264 C CG . LYS J 1 37 ? 172.582 155.242 93.477 1.00 66.94 37 J 1
|
| 545 |
+
ATOM 265 C CD . LYS J 1 37 ? 172.450 154.552 94.823 1.00 66.94 37 J 1
|
| 546 |
+
ATOM 266 C CE . LYS J 1 37 ? 173.808 154.194 95.400 1.00 66.94 37 J 1
|
| 547 |
+
ATOM 267 N NZ . LYS J 1 37 ? 173.680 153.478 96.700 1.00 66.94 37 J 1
|
| 548 |
+
ATOM 268 N N . PRO J 1 38 ? 167.768 154.426 92.850 1.00 68.68 38 J 1
|
| 549 |
+
ATOM 269 C CA . PRO J 1 38 ? 166.442 154.759 92.315 1.00 68.68 38 J 1
|
| 550 |
+
ATOM 270 C C . PRO J 1 38 ? 165.804 155.974 92.952 1.00 68.68 38 J 1
|
| 551 |
+
ATOM 271 O O . PRO J 1 38 ? 165.061 156.684 92.265 1.00 68.68 38 J 1
|
| 552 |
+
ATOM 272 C CB . PRO J 1 38 ? 165.630 153.501 92.616 1.00 68.68 38 J 1
|
| 553 |
+
ATOM 273 C CG . PRO J 1 38 ? 166.222 153.021 93.902 1.00 68.68 38 J 1
|
| 554 |
+
ATOM 274 C CD . PRO J 1 38 ? 167.701 153.332 93.834 1.00 68.68 38 J 1
|
| 555 |
+
ATOM 275 N N . SER J 1 39 ? 166.056 156.240 94.230 1.00 70.54 39 J 1
|
| 556 |
+
ATOM 276 C CA . SER J 1 39 ? 165.383 157.320 94.933 1.00 70.54 39 J 1
|
| 557 |
+
ATOM 277 C C . SER J 1 39 ? 166.204 158.596 94.992 1.00 70.54 39 J 1
|
| 558 |
+
ATOM 278 O O . SER J 1 39 ? 165.705 159.612 95.488 1.00 70.54 39 J 1
|
| 559 |
+
ATOM 279 C CB . SER J 1 39 ? 165.027 156.887 96.360 1.00 70.54 39 J 1
|
| 560 |
+
ATOM 280 O OG . SER J 1 39 ? 166.196 156.601 97.104 1.00 70.54 39 J 1
|
| 561 |
+
ATOM 281 N N . ASP J 1 40 ? 167.425 158.579 94.500 1.00 71.51 40 J 1
|
| 562 |
+
ATOM 282 C CA . ASP J 1 40 ? 168.310 159.702 94.730 1.00 71.51 40 J 1
|
| 563 |
+
ATOM 283 C C . ASP J 1 40 ? 167.868 160.912 93.909 1.00 71.51 40 J 1
|
| 564 |
+
ATOM 284 O O . ASP J 1 40 ? 167.348 160.766 92.800 1.00 71.51 40 J 1
|
| 565 |
+
ATOM 285 C CB . ASP J 1 40 ? 169.741 159.324 94.374 1.00 71.51 40 J 1
|
| 566 |
+
ATOM 286 C CG . ASP J 1 40 ? 170.519 158.829 95.569 1.00 71.51 40 J 1
|
| 567 |
+
ATOM 287 O OD1 . ASP J 1 40 ? 170.038 159.024 96.701 1.00 71.51 40 J 1
|
| 568 |
+
ATOM 288 O OD2 . ASP J 1 40 ? 171.606 158.245 95.379 1.00 71.51 40 J 1
|
| 569 |
+
ATOM 289 N N . PRO J 1 41 ? 168.040 162.115 94.445 1.00 72.15 41 J 1
|
| 570 |
+
ATOM 290 C CA . PRO J 1 41 ? 167.725 163.323 93.677 1.00 72.15 41 J 1
|
| 571 |
+
ATOM 291 C C . PRO J 1 41 ? 168.792 163.594 92.630 1.00 72.15 41 J 1
|
| 572 |
+
ATOM 292 O O . PRO J 1 41 ? 169.806 162.902 92.531 1.00 72.15 41 J 1
|
| 573 |
+
ATOM 293 C CB . PRO J 1 41 ? 167.709 164.427 94.737 1.00 72.15 41 J 1
|
| 574 |
+
ATOM 294 C CG . PRO J 1 41 ? 167.558 163.713 96.031 1.00 72.15 41 J 1
|
| 575 |
+
ATOM 295 C CD . PRO J 1 41 ? 168.278 162.420 95.862 1.00 72.15 41 J 1
|
| 576 |
+
ATOM 296 N N . ALA J 1 42 ? 168.537 164.627 91.831 1.00 68.90 42 J 1
|
| 577 |
+
ATOM 297 C CA . ALA J 1 42 ? 169.449 165.183 90.837 1.00 68.90 42 J 1
|
| 578 |
+
ATOM 298 C C . ALA J 1 42 ? 169.710 164.237 89.674 1.00 68.90 42 J 1
|
| 579 |
+
ATOM 299 O O . ALA J 1 42 ? 170.388 164.632 88.718 1.00 68.90 42 J 1
|
| 580 |
+
ATOM 300 C CB . ALA J 1 42 ? 170.795 165.605 91.445 1.00 68.90 42 J 1
|
| 581 |
+
ATOM 301 N N . LEU J 1 43 ? 169.199 163.008 89.712 1.00 66.88 43 J 1
|
| 582 |
+
ATOM 302 C CA . LEU J 1 43 ? 169.214 162.168 88.523 1.00 66.88 43 J 1
|
| 583 |
+
ATOM 303 C C . LEU J 1 43 ? 167.793 161.722 88.216 1.00 66.88 43 J 1
|
| 584 |
+
ATOM 304 O O . LEU J 1 43 ? 167.436 161.561 87.048 1.00 66.88 43 J 1
|
| 585 |
+
ATOM 305 C CB . LEU J 1 43 ? 170.136 160.956 88.678 1.00 66.88 43 J 1
|
| 586 |
+
ATOM 306 C CG . LEU J 1 43 ? 169.723 159.783 89.565 1.00 66.88 43 J 1
|
| 587 |
+
ATOM 307 C CD1 . LEU J 1 43 ? 170.578 158.575 89.251 1.00 66.88 43 J 1
|
| 588 |
+
ATOM 308 C CD2 . LEU J 1 43 ? 169.875 160.147 91.011 1.00 66.88 43 J 1
|
| 589 |
+
ATOM 309 N N . LEU J 1 44 ? 166.976 161.526 89.255 1.00 62.81 44 J 1
|
| 590 |
+
ATOM 310 C CA . LEU J 1 44 ? 165.564 161.231 89.034 1.00 62.81 44 J 1
|
| 591 |
+
ATOM 311 C C . LEU J 1 44 ? 164.891 162.349 88.255 1.00 62.81 44 J 1
|
| 592 |
+
ATOM 312 O O . LEU J 1 44 ? 164.229 162.103 87.240 1.00 62.81 44 J 1
|
| 593 |
+
ATOM 313 C CB . LEU J 1 44 ? 164.850 161.025 90.366 1.00 62.81 44 J 1
|
| 594 |
+
ATOM 314 C CG . LEU J 1 44 ? 164.662 159.603 90.876 1.00 62.81 44 J 1
|
| 595 |
+
ATOM 315 C CD1 . LEU J 1 44 ? 164.144 159.655 92.300 1.00 62.81 44 J 1
|
| 596 |
+
ATOM 316 C CD2 . LEU J 1 44 ? 163.706 158.844 89.980 1.00 62.81 44 J 1
|
| 597 |
+
ATOM 317 N N . ALA J 1 45 ? 165.051 163.589 88.717 1.00 63.51 45 J 1
|
| 598 |
+
ATOM 318 C CA . ALA J 1 45 ? 164.565 164.727 87.951 1.00 63.51 45 J 1
|
| 599 |
+
ATOM 319 C C . ALA J 1 45 ? 165.278 164.805 86.611 1.00 63.51 45 J 1
|
| 600 |
+
ATOM 320 O O . ALA J 1 45 ? 164.660 165.085 85.577 1.00 63.51 45 J 1
|
| 601 |
+
ATOM 321 C CB . ALA J 1 45 ? 164.759 166.015 88.748 1.00 63.51 45 J 1
|
| 602 |
+
ATOM 322 N N . ALA J 1 46 ? 166.587 164.547 86.611 1.00 63.88 46 J 1
|
| 603 |
+
ATOM 323 C CA . ALA J 1 46 ? 167.322 164.470 85.356 1.00 63.88 46 J 1
|
| 604 |
+
ATOM 324 C C . ALA J 1 46 ? 166.799 163.335 84.489 1.00 63.88 46 J 1
|
| 605 |
+
ATOM 325 O O . ALA J 1 46 ? 166.675 163.486 83.270 1.00 63.88 46 J 1
|
| 606 |
+
ATOM 326 C CB . ALA J 1 46 ? 168.815 164.297 85.627 1.00 63.88 46 J 1
|
| 607 |
+
ATOM 327 N N . TYR J 1 47 ? 166.483 162.190 85.100 1.00 60.60 47 J 1
|
| 608 |
+
ATOM 328 C CA . TYR J 1 47 ? 165.886 161.089 84.350 1.00 60.60 47 J 1
|
| 609 |
+
ATOM 329 C C . TYR J 1 47 ? 164.618 161.528 83.639 1.00 60.60 47 J 1
|
| 610 |
+
ATOM 330 O O . TYR J 1 47 ? 164.476 161.336 82.427 1.00 60.60 47 J 1
|
| 611 |
+
ATOM 331 C CB . TYR J 1 47 ? 165.579 159.921 85.282 1.00 60.60 47 J 1
|
| 612 |
+
ATOM 332 C CG . TYR J 1 47 ? 164.985 158.730 84.578 1.00 60.60 47 J 1
|
| 613 |
+
ATOM 333 C CD1 . TYR J 1 47 ? 165.771 157.885 83.811 1.00 60.60 47 J 1
|
| 614 |
+
ATOM 334 C CD2 . TYR J 1 47 ? 163.629 158.457 84.675 1.00 60.60 47 J 1
|
| 615 |
+
ATOM 335 C CE1 . TYR J 1 47 ? 165.223 156.798 83.168 1.00 60.60 47 J 1
|
| 616 |
+
ATOM 336 C CE2 . TYR J 1 47 ? 163.073 157.376 84.037 1.00 60.60 47 J 1
|
| 617 |
+
ATOM 337 C CZ . TYR J 1 47 ? 163.872 156.550 83.285 1.00 60.60 47 J 1
|
| 618 |
+
ATOM 338 O OH . TYR J 1 47 ? 163.317 155.471 82.646 1.00 60.60 47 J 1
|
| 619 |
+
ATOM 339 N N . GLN J 1 48 ? 163.681 162.118 84.380 1.00 61.22 48 J 1
|
| 620 |
+
ATOM 340 C CA . GLN J 1 48 ? 162.418 162.506 83.769 1.00 61.22 48 J 1
|
| 621 |
+
ATOM 341 C C . GLN J 1 48 ? 162.618 163.572 82.703 1.00 61.22 48 J 1
|
| 622 |
+
ATOM 342 O O . GLN J 1 48 ? 162.021 163.485 81.623 1.00 61.22 48 J 1
|
| 623 |
+
ATOM 343 C CB . GLN J 1 48 ? 161.441 163.000 84.832 1.00 61.22 48 J 1
|
| 624 |
+
ATOM 344 C CG . GLN J 1 48 ? 160.073 163.333 84.276 1.00 61.22 48 J 1
|
| 625 |
+
ATOM 345 C CD . GLN J 1 48 ? 159.096 163.765 85.344 1.00 61.22 48 J 1
|
| 626 |
+
ATOM 346 O OE1 . GLN J 1 48 ? 159.445 163.860 86.519 1.00 61.22 48 J 1
|
| 627 |
+
ATOM 347 N NE2 . GLN J 1 48 ? 157.858 164.028 84.941 1.00 61.22 48 J 1
|
| 628 |
+
ATOM 348 N N . SER J 1 49 ? 163.461 164.571 82.975 1.00 66.01 49 J 1
|
| 629 |
+
ATOM 349 C CA . SER J 1 49 ? 163.666 165.643 82.010 1.00 66.01 49 J 1
|
| 630 |
+
ATOM 350 C C . SER J 1 49 ? 164.298 165.117 80.729 1.00 66.01 49 J 1
|
| 631 |
+
ATOM 351 O O . SER J 1 49 ? 163.843 165.437 79.628 1.00 66.01 49 J 1
|
| 632 |
+
ATOM 352 C CB . SER J 1 49 ? 164.529 166.744 82.623 1.00 66.01 49 J 1
|
| 633 |
+
ATOM 353 O OG . SER J 1 49 ? 164.839 167.732 81.658 1.00 66.01 49 J 1
|
| 634 |
+
ATOM 354 N N . LYS J 1 50 ? 165.348 164.301 80.851 1.00 62.23 50 J 1
|
| 635 |
+
ATOM 355 C CA . LYS J 1 50 ? 165.992 163.755 79.662 1.00 62.23 50 J 1
|
| 636 |
+
ATOM 356 C C . LYS J 1 50 ? 165.074 162.806 78.908 1.00 62.23 50 J 1
|
| 637 |
+
ATOM 357 O O . LYS J 1 50 ? 165.080 162.796 77.674 1.00 62.23 50 J 1
|
| 638 |
+
ATOM 358 C CB . LYS J 1 50 ? 167.292 163.045 80.036 1.00 62.23 50 J 1
|
| 639 |
+
ATOM 359 C CG . LYS J 1 50 ? 168.320 163.948 80.688 1.00 62.23 50 J 1
|
| 640 |
+
ATOM 360 C CD . LYS J 1 50 ? 168.804 165.014 79.725 1.00 62.23 50 J 1
|
| 641 |
+
ATOM 361 C CE . LYS J 1 50 ? 169.815 165.927 80.391 1.00 62.23 50 J 1
|
| 642 |
+
ATOM 362 N NZ . LYS J 1 50 ? 171.093 165.218 80.672 1.00 62.23 50 J 1
|
| 643 |
+
ATOM 363 N N . LEU J 1 51 ? 164.282 162.004 79.620 1.00 55.13 51 J 1
|
| 644 |
+
ATOM 364 C CA . LEU J 1 51 ? 163.386 161.078 78.942 1.00 55.13 51 J 1
|
| 645 |
+
ATOM 365 C C . LEU J 1 51 ? 162.306 161.830 78.175 1.00 55.13 51 J 1
|
| 646 |
+
ATOM 366 O O . LEU J 1 51 ? 161.984 161.482 77.034 1.00 55.13 51 J 1
|
| 647 |
+
ATOM 367 C CB . LEU J 1 51 ? 162.773 160.118 79.955 1.00 55.13 51 J 1
|
| 648 |
+
ATOM 368 C CG . LEU J 1 51 ? 161.865 159.044 79.373 1.00 55.13 51 J 1
|
| 649 |
+
ATOM 369 C CD1 . LEU J 1 51 ? 162.675 158.158 78.450 1.00 55.13 51 J 1
|
| 650 |
+
ATOM 370 C CD2 . LEU J 1 51 ? 161.246 158.227 80.487 1.00 55.13 51 J 1
|
| 651 |
+
ATOM 371 N N . SER J 1 52 ? 161.739 162.876 78.783 1.00 58.66 52 J 1
|
| 652 |
+
ATOM 372 C CA . SER J 1 52 ? 160.769 163.700 78.069 1.00 58.66 52 J 1
|
| 653 |
+
ATOM 373 C C . SER J 1 52 ? 161.418 164.423 76.896 1.00 58.66 52 J 1
|
| 654 |
+
ATOM 374 O O . SER J 1 52 ? 160.815 164.553 75.825 1.00 58.66 52 J 1
|
| 655 |
+
ATOM 375 C CB . SER J 1 52 ? 160.119 164.699 79.023 1.00 58.66 52 J 1
|
| 656 |
+
ATOM 376 O OG . SER J 1 52 ? 159.266 164.041 79.940 1.00 58.66 52 J 1
|
| 657 |
+
ATOM 377 N N . GLU J 1 53 ? 162.646 164.910 77.081 1.00 65.81 53 J 1
|
| 658 |
+
ATOM 378 C CA . GLU J 1 53 ? 163.360 165.549 75.985 1.00 65.81 53 J 1
|
| 659 |
+
ATOM 379 C C . GLU J 1 53 ? 163.519 164.593 74.816 1.00 65.81 53 J 1
|
| 660 |
+
ATOM 380 O O . GLU J 1 53 ? 163.285 164.966 73.663 1.00 65.81 53 J 1
|
| 661 |
+
ATOM 381 C CB . GLU J 1 53 ? 164.729 166.027 76.468 1.00 65.81 53 J 1
|
| 662 |
+
ATOM 382 C CG . GLU J 1 53 ? 164.823 167.501 76.834 1.00 65.81 53 J 1
|
| 663 |
+
ATOM 383 C CD . GLU J 1 53 ? 164.613 168.437 75.659 1.00 65.81 53 J 1
|
| 664 |
+
ATOM 384 O OE1 . GLU J 1 53 ? 164.395 167.965 74.524 1.00 65.81 53 J 1
|
| 665 |
+
ATOM 385 O OE2 . GLU J 1 53 ? 164.659 169.667 75.875 1.00 65.81 53 J 1
|
| 666 |
+
ATOM 386 N N . TYR J 1 54 ? 163.901 163.351 75.104 1.00 59.32 54 J 1
|
| 667 |
+
ATOM 387 C CA . TYR J 1 54 ? 164.070 162.346 74.065 1.00 59.32 54 J 1
|
| 668 |
+
ATOM 388 C C . TYR J 1 54 ? 162.742 162.013 73.396 1.00 59.32 54 J 1
|
| 669 |
+
ATOM 389 O O . TYR J 1 54 ? 162.683 161.828 72.175 1.00 59.32 54 J 1
|
| 670 |
+
ATOM 390 C CB . TYR J 1 54 ? 164.710 161.104 74.676 1.00 59.32 54 J 1
|
| 671 |
+
ATOM 391 C CG . TYR J 1 54 ? 164.986 159.991 73.707 1.00 59.32 54 J 1
|
| 672 |
+
ATOM 392 C CD1 . TYR J 1 54 ? 166.049 160.070 72.828 1.00 59.32 54 J 1
|
| 673 |
+
ATOM 393 C CD2 . TYR J 1 54 ? 164.208 158.845 73.697 1.00 59.32 54 J 1
|
| 674 |
+
ATOM 394 C CE1 . TYR J 1 54 ? 166.316 159.055 71.945 1.00 59.32 54 J 1
|
| 675 |
+
ATOM 395 C CE2 . TYR J 1 54 ? 164.470 157.819 72.819 1.00 59.32 54 J 1
|
| 676 |
+
ATOM 396 C CZ . TYR J 1 54 ? 165.527 157.929 71.944 1.00 59.32 54 J 1
|
| 677 |
+
ATOM 397 O OH . TYR J 1 54 ? 165.800 156.912 71.061 1.00 59.32 54 J 1
|
| 678 |
+
ATOM 398 N N . ASN J 1 55 ? 161.668 161.931 74.183 1.00 55.92 55 J 1
|
| 679 |
+
ATOM 399 C CA . ASN J 1 55 ? 160.344 161.659 73.629 1.00 55.92 55 J 1
|
| 680 |
+
ATOM 400 C C . ASN J 1 55 ? 159.925 162.748 72.647 1.00 55.92 55 J 1
|
| 681 |
+
ATOM 401 O O . ASN J 1 55 ? 159.524 162.458 71.511 1.00 55.92 55 J 1
|
| 682 |
+
ATOM 402 C CB . ASN J 1 55 ? 159.340 161.529 74.777 1.00 55.92 55 J 1
|
| 683 |
+
ATOM 403 C CG . ASN J 1 55 ? 157.922 161.278 74.306 1.00 55.92 55 J 1
|
| 684 |
+
ATOM 404 O OD1 . ASN J 1 55 ? 157.659 161.123 73.117 1.00 55.92 55 J 1
|
| 685 |
+
ATOM 405 N ND2 . ASN J 1 55 ? 156.998 161.213 75.253 1.00 55.92 55 J 1
|
| 686 |
+
ATOM 406 N N . LEU J 1 56 ? 160.012 164.010 73.071 1.00 57.85 56 J 1
|
| 687 |
+
ATOM 407 C CA . LEU J 1 56 ? 159.659 165.115 72.183 1.00 57.85 56 J 1
|
| 688 |
+
ATOM 408 C C . LEU J 1 56 ? 160.587 165.185 70.980 1.00 57.85 56 J 1
|
| 689 |
+
ATOM 409 O O . LEU J 1 56 ? 160.148 165.503 69.871 1.00 57.85 56 J 1
|
| 690 |
+
ATOM 410 C CB . LEU J 1 56 ? 159.665 166.437 72.945 1.00 57.85 56 J 1
|
| 691 |
+
ATOM 411 C CG . LEU J 1 56 ? 158.428 166.781 73.772 1.00 57.85 56 J 1
|
| 692 |
+
ATOM 412 C CD1 . LEU J 1 56 ? 158.257 165.920 74.998 1.00 57.85 56 J 1
|
| 693 |
+
ATOM 413 C CD2 . LEU J 1 56 ? 158.539 168.224 74.179 1.00 57.85 56 J 1
|
| 694 |
+
ATOM 414 N N . TYR J 1 57 ? 161.872 164.895 71.176 1.00 60.05 57 J 1
|
| 695 |
+
ATOM 415 C CA . TYR J 1 57 ? 162.800 164.844 70.054 1.00 60.05 57 J 1
|
| 696 |
+
ATOM 416 C C . TYR J 1 57 ? 162.362 163.824 69.013 1.00 60.05 57 J 1
|
| 697 |
+
ATOM 417 O O . TYR J 1 57 ? 162.299 164.134 67.817 1.00 60.05 57 J 1
|
| 698 |
+
ATOM 418 C CB . TYR J 1 57 ? 164.203 164.534 70.578 1.00 60.05 57 J 1
|
| 699 |
+
ATOM 419 C CG . TYR J 1 57 ? 165.239 164.289 69.513 1.00 60.05 57 J 1
|
| 700 |
+
ATOM 420 C CD1 . TYR J 1 57 ? 165.328 163.058 68.881 1.00 60.05 57 J 1
|
| 701 |
+
ATOM 421 C CD2 . TYR J 1 57 ? 166.114 165.288 69.127 1.00 60.05 57 J 1
|
| 702 |
+
ATOM 422 C CE1 . TYR J 1 57 ? 166.257 162.825 67.909 1.00 60.05 57 J 1
|
| 703 |
+
ATOM 423 C CE2 . TYR J 1 57 ? 167.052 165.063 68.149 1.00 60.05 57 J 1
|
| 704 |
+
ATOM 424 C CZ . TYR J 1 57 ? 167.118 163.828 67.545 1.00 60.05 57 J 1
|
| 705 |
+
ATOM 425 O OH . TYR J 1 57 ? 168.044 163.579 66.567 1.00 60.05 57 J 1
|
| 706 |
+
ATOM 426 N N . ARG J 1 58 ? 162.069 162.598 69.446 1.00 58.38 58 J 1
|
| 707 |
+
ATOM 427 C CA . ARG J 1 58 ? 161.680 161.562 68.498 1.00 58.38 58 J 1
|
| 708 |
+
ATOM 428 C C . ARG J 1 58 ? 160.373 161.916 67.804 1.00 58.38 58 J 1
|
| 709 |
+
ATOM 429 O O . ARG J 1 58 ? 160.238 161.726 66.587 1.00 58.38 58 J 1
|
| 710 |
+
ATOM 430 C CB . ARG J 1 58 ? 161.566 160.217 69.208 1.00 58.38 58 J 1
|
| 711 |
+
ATOM 431 C CG . ARG J 1 58 ? 162.900 159.553 69.491 1.00 58.38 58 J 1
|
| 712 |
+
ATOM 432 C CD . ARG J 1 58 ? 163.871 159.707 68.335 1.00 58.38 58 J 1
|
| 713 |
+
ATOM 433 N NE . ARG J 1 58 ? 165.241 159.437 68.753 1.00 58.38 58 J 1
|
| 714 |
+
ATOM 434 C CZ . ARG J 1 58 ? 166.293 159.472 67.948 1.00 58.38 58 J 1
|
| 715 |
+
ATOM 435 N NH1 . ARG J 1 58 ? 166.171 159.760 66.663 1.00 58.38 58 J 1
|
| 716 |
+
ATOM 436 N NH2 . ARG J 1 58 ? 167.498 159.214 68.445 1.00 58.38 58 J 1
|
| 717 |
+
ATOM 437 N N . ASN J 1 59 ? 159.399 162.432 68.558 1.00 58.16 59 J 1
|
| 718 |
+
ATOM 438 C CA . ASN J 1 59 ? 158.133 162.817 67.945 1.00 58.16 59 J 1
|
| 719 |
+
ATOM 439 C C . ASN J 1 59 ? 158.327 163.928 66.924 1.00 58.16 59 J 1
|
| 720 |
+
ATOM 440 O O . ASN J 1 59 ? 157.735 163.893 65.839 1.00 58.16 59 J 1
|
| 721 |
+
ATOM 441 C CB . ASN J 1 59 ? 157.133 163.240 69.017 1.00 58.16 59 J 1
|
| 722 |
+
ATOM 442 C CG . ASN J 1 59 ? 156.401 162.065 69.619 1.00 58.16 59 J 1
|
| 723 |
+
ATOM 443 O OD1 . ASN J 1 59 ? 156.905 161.403 70.521 1.00 58.16 59 J 1
|
| 724 |
+
ATOM 444 N ND2 . ASN J 1 59 ? 155.203 161.796 69.117 1.00 58.16 59 J 1
|
| 725 |
+
ATOM 445 N N . ALA J 1 60 ? 159.154 164.925 67.250 1.00 62.06 60 J 1
|
| 726 |
+
ATOM 446 C CA . ALA J 1 60 ? 159.407 166.012 66.314 1.00 62.06 60 J 1
|
| 727 |
+
ATOM 447 C C . ALA J 1 60 ? 160.081 165.504 65.052 1.00 62.06 60 J 1
|
| 728 |
+
ATOM 448 O O . ALA J 1 60 ? 159.709 165.896 63.940 1.00 62.06 60 J 1
|
| 729 |
+
ATOM 449 C CB . ALA J 1 60 ? 160.257 167.092 66.980 1.00 62.06 60 J 1
|
| 730 |
+
ATOM 450 N N . GLN J 1 61 ? 161.067 164.621 65.203 1.00 65.39 61 J 1
|
| 731 |
+
ATOM 451 C CA . GLN J 1 61 ? 161.748 164.072 64.037 1.00 65.39 61 J 1
|
| 732 |
+
ATOM 452 C C . GLN J 1 61 ? 160.774 163.310 63.148 1.00 65.39 61 J 1
|
| 733 |
+
ATOM 453 O O . GLN J 1 61 ? 160.735 163.512 61.925 1.00 65.39 61 J 1
|
| 734 |
+
ATOM 454 C CB . GLN J 1 61 ? 162.895 163.171 64.494 1.00 65.39 61 J 1
|
| 735 |
+
ATOM 455 C CG . GLN J 1 61 ? 164.044 163.067 63.519 1.00 65.39 61 J 1
|
| 736 |
+
ATOM 456 C CD . GLN J 1 61 ? 165.192 162.262 64.080 1.00 65.39 61 J 1
|
| 737 |
+
ATOM 457 O OE1 . GLN J 1 61 ? 166.240 162.807 64.420 1.00 65.39 61 J 1
|
| 738 |
+
ATOM 458 N NE2 . GLN J 1 61 ? 164.998 160.957 64.189 1.00 65.39 61 J 1
|
| 739 |
+
ATOM 459 N N . SER J 1 62 ? 159.959 162.442 63.753 1.00 64.39 62 J 1
|
| 740 |
+
ATOM 460 C CA . SER J 1 62 ? 159.025 161.644 62.969 1.00 64.39 62 J 1
|
| 741 |
+
ATOM 461 C C . SER J 1 62 ? 157.998 162.522 62.267 1.00 64.39 62 J 1
|
| 742 |
+
ATOM 462 O O . SER J 1 62 ? 157.716 162.331 61.078 1.00 64.39 62 J 1
|
| 743 |
+
ATOM 463 C CB . SER J 1 62 ? 158.333 160.619 63.865 1.00 64.39 62 J 1
|
| 744 |
+
ATOM 464 O OG . SER J 1 62 ? 157.410 159.843 63.125 1.00 64.39 62 J 1
|
| 745 |
+
ATOM 465 N N . ASN J 1 63 ? 157.438 163.504 62.976 1.00 65.16 63 J 1
|
| 746 |
+
ATOM 466 C CA . ASN J 1 63 ? 156.437 164.361 62.357 1.00 65.16 63 J 1
|
| 747 |
+
ATOM 467 C C . ASN J 1 63 ? 157.033 165.219 61.252 1.00 65.16 63 J 1
|
| 748 |
+
ATOM 468 O O . ASN J 1 63 ? 156.389 165.421 60.216 1.00 65.16 63 J 1
|
| 749 |
+
ATOM 469 C CB . ASN J 1 63 ? 155.767 165.233 63.413 1.00 65.16 63 J 1
|
| 750 |
+
ATOM 470 C CG . ASN J 1 63 ? 154.853 164.439 64.316 1.00 65.16 63 J 1
|
| 751 |
+
ATOM 471 O OD1 . ASN J 1 63 ? 154.525 163.290 64.026 1.00 65.16 63 J 1
|
| 752 |
+
ATOM 472 N ND2 . ASN J 1 63 ? 154.434 165.045 65.416 1.00 65.16 63 J 1
|
| 753 |
+
ATOM 473 N N . THR J 1 64 ? 158.252 165.729 61.444 1.00 66.60 64 J 1
|
| 754 |
+
ATOM 474 C CA . THR J 1 64 ? 158.875 166.543 60.408 1.00 66.60 64 J 1
|
| 755 |
+
ATOM 475 C C . THR J 1 64 ? 159.147 165.725 59.153 1.00 66.60 64 J 1
|
| 756 |
+
ATOM 476 O O . THR J 1 64 ? 158.846 166.169 58.035 1.00 66.60 64 J 1
|
| 757 |
+
ATOM 477 C CB . THR J 1 64 ? 160.169 167.158 60.935 1.00 66.60 64 J 1
|
| 758 |
+
ATOM 478 O OG1 . THR J 1 64 ? 159.877 167.977 62.072 1.00 66.60 64 J 1
|
| 759 |
+
ATOM 479 C CG2 . THR J 1 64 ? 160.819 168.011 59.865 1.00 66.60 64 J 1
|
| 760 |
+
ATOM 480 N N . VAL J 1 65 ? 159.707 164.523 59.310 1.00 64.00 65 J 1
|
| 761 |
+
ATOM 481 C CA . VAL J 1 65 ? 159.978 163.718 58.124 1.00 64.00 65 J 1
|
| 762 |
+
ATOM 482 C C . VAL J 1 65 ? 158.671 163.316 57.452 1.00 64.00 65 J 1
|
| 763 |
+
ATOM 483 O O . VAL J 1 65 ? 158.580 163.285 56.220 1.00 64.00 65 J 1
|
| 764 |
+
ATOM 484 C CB . VAL J 1 65 ? 160.858 162.499 58.464 1.00 64.00 65 J 1
|
| 765 |
+
ATOM 485 C CG1 . VAL J 1 65 ? 162.203 162.957 58.999 1.00 64.00 65 J 1
|
| 766 |
+
ATOM 486 C CG2 . VAL J 1 65 ? 160.176 161.571 59.442 1.00 64.00 65 J 1
|
| 767 |
+
ATOM 487 N N . LYS J 1 66 ? 157.626 163.047 58.241 1.00 65.12 66 J 1
|
| 768 |
+
ATOM 488 C CA . LYS J 1 66 ? 156.341 162.691 57.649 1.00 65.12 66 J 1
|
| 769 |
+
ATOM 489 C C . LYS J 1 66 ? 155.745 163.847 56.855 1.00 65.12 66 J 1
|
| 770 |
+
ATOM 490 O O . LYS J 1 66 ? 155.240 163.645 55.745 1.00 65.12 66 J 1
|
| 771 |
+
ATOM 491 C CB . LYS J 1 66 ? 155.366 162.235 58.733 1.00 65.12 66 J 1
|
| 772 |
+
ATOM 492 C CG . LYS J 1 66 ? 153.992 161.855 58.202 1.00 65.12 66 J 1
|
| 773 |
+
ATOM 493 C CD . LYS J 1 66 ? 154.088 160.891 57.032 1.00 65.12 66 J 1
|
| 774 |
+
ATOM 494 C CE . LYS J 1 66 ? 152.711 160.542 56.496 1.00 65.12 66 J 1
|
| 775 |
+
ATOM 495 N NZ . LYS J 1 66 ? 151.754 160.214 57.587 1.00 65.12 66 J 1
|
| 776 |
+
ATOM 496 N N . VAL J 1 67 ? 155.779 165.064 57.402 1.00 65.92 67 J 1
|
| 777 |
+
ATOM 497 C CA . VAL J 1 67 ? 155.163 166.185 56.696 1.00 65.92 67 J 1
|
| 778 |
+
ATOM 498 C C . VAL J 1 67 ? 155.958 166.528 55.442 1.00 65.92 67 J 1
|
| 779 |
+
ATOM 499 O O . VAL J 1 67 ? 155.381 166.863 54.397 1.00 65.92 67 J 1
|
| 780 |
+
ATOM 500 C CB . VAL J 1 67 ? 154.993 167.401 57.629 1.00 65.92 67 J 1
|
| 781 |
+
ATOM 501 C CG1 . VAL J 1 67 ? 156.328 167.937 58.097 1.00 65.92 67 J 1
|
| 782 |
+
ATOM 502 C CG2 . VAL J 1 67 ? 154.200 168.492 56.929 1.00 65.92 67 J 1
|
| 783 |
+
ATOM 503 N N . PHE J 1 68 ? 157.288 166.435 55.509 1.00 66.56 68 J 1
|
| 784 |
+
ATOM 504 C CA . PHE J 1 68 ? 158.076 166.682 54.308 1.00 66.56 68 J 1
|
| 785 |
+
ATOM 505 C C . PHE J 1 68 ? 157.826 165.606 53.260 1.00 66.56 68 J 1
|
| 786 |
+
ATOM 506 O O . PHE J 1 68 ? 157.772 165.899 52.059 1.00 66.56 68 J 1
|
| 787 |
+
ATOM 507 C CB . PHE J 1 68 ? 159.558 166.785 54.657 1.00 66.56 68 J 1
|
| 788 |
+
ATOM 508 C CG . PHE J 1 68 ? 159.991 168.177 55.012 1.00 66.56 68 J 1
|
| 789 |
+
ATOM 509 C CD1 . PHE J 1 68 ? 160.099 168.568 56.333 1.00 66.56 68 J 1
|
| 790 |
+
ATOM 510 C CD2 . PHE J 1 68 ? 160.268 169.101 54.022 1.00 66.56 68 J 1
|
| 791 |
+
ATOM 511 C CE1 . PHE J 1 68 ? 160.490 169.850 56.660 1.00 66.56 68 J 1
|
| 792 |
+
ATOM 512 C CE2 . PHE J 1 68 ? 160.658 170.384 54.343 1.00 66.56 68 J 1
|
| 793 |
+
ATOM 513 C CZ . PHE J 1 68 ? 160.769 170.758 55.664 1.00 66.56 68 J 1
|
| 794 |
+
ATOM 514 N N . LYS J 1 69 ? 157.646 164.356 53.694 1.00 70.04 69 J 1
|
| 795 |
+
ATOM 515 C CA . LYS J 1 69 ? 157.283 163.302 52.755 1.00 70.04 69 J 1
|
| 796 |
+
ATOM 516 C C . LYS J 1 69 ? 155.929 163.584 52.123 1.00 70.04 69 J 1
|
| 797 |
+
ATOM 517 O O . LYS J 1 69 ? 155.731 163.326 50.934 1.00 70.04 69 J 1
|
| 798 |
+
ATOM 518 C CB . LYS J 1 69 ? 157.291 161.944 53.465 1.00 70.04 69 J 1
|
| 799 |
+
ATOM 519 C CG . LYS J 1 69 ? 157.067 160.718 52.570 1.00 70.04 69 J 1
|
| 800 |
+
ATOM 520 C CD . LYS J 1 69 ? 155.593 160.436 52.289 1.00 70.04 69 J 1
|
| 801 |
+
ATOM 521 C CE . LYS J 1 69 ? 155.424 159.353 51.239 1.00 70.04 69 J 1
|
| 802 |
+
ATOM 522 N NZ . LYS J 1 69 ? 153.999 158.953 51.085 1.00 70.04 69 J 1
|
| 803 |
+
ATOM 523 N N . ASP J 1 70 ? 154.979 164.093 52.908 1.00 70.15 70 J 1
|
| 804 |
+
ATOM 524 C CA . ASP J 1 70 ? 153.667 164.418 52.356 1.00 70.15 70 J 1
|
| 805 |
+
ATOM 525 C C . ASP J 1 70 ? 153.770 165.503 51.293 1.00 70.15 70 J 1
|
| 806 |
+
ATOM 526 O O . ASP J 1 70 ? 153.172 165.386 50.216 1.00 70.15 70 J 1
|
| 807 |
+
ATOM 527 C CB . ASP J 1 70 ? 152.719 164.850 53.472 1.00 70.15 70 J 1
|
| 808 |
+
ATOM 528 C CG . ASP J 1 70 ? 152.353 163.710 54.396 1.00 70.15 70 J 1
|
| 809 |
+
ATOM 529 O OD1 . ASP J 1 70 ? 152.337 162.552 53.930 1.00 70.15 70 J 1
|
| 810 |
+
ATOM 530 O OD2 . ASP J 1 70 ? 152.082 163.970 55.587 1.00 70.15 70 J 1
|
| 811 |
+
ATOM 531 N N . ILE J 1 71 ? 154.538 166.558 51.574 1.00 64.31 71 J 1
|
| 812 |
+
ATOM 532 C CA . ILE J 1 71 ? 154.721 167.619 50.588 1.00 64.31 71 J 1
|
| 813 |
+
ATOM 533 C C . ILE J 1 71 ? 155.375 167.070 49.326 1.00 64.31 71 J 1
|
| 814 |
+
ATOM 534 O O . ILE J 1 71 ? 154.941 167.362 48.203 1.00 64.31 71 J 1
|
| 815 |
+
ATOM 535 C CB . ILE J 1 71 ? 155.545 168.772 51.188 1.00 64.31 71 J 1
|
| 816 |
+
ATOM 536 C CG1 . ILE J 1 71 ? 154.860 169.327 52.435 1.00 64.31 71 J 1
|
| 817 |
+
ATOM 537 C CG2 . ILE J 1 71 ? 155.751 169.866 50.159 1.00 64.31 71 J 1
|
| 818 |
+
ATOM 538 C CD1 . ILE J 1 71 ? 155.778 170.127 53.325 1.00 64.31 71 J 1
|
| 819 |
+
ATOM 539 N N . ASP J 1 72 ? 156.423 166.261 49.492 1.00 68.85 72 J 1
|
| 820 |
+
ATOM 540 C CA . ASP J 1 72 ? 157.144 165.727 48.343 1.00 68.85 72 J 1
|
| 821 |
+
ATOM 541 C C . ASP J 1 72 ? 156.266 164.795 47.517 1.00 68.85 72 J 1
|
| 822 |
+
ATOM 542 O O . ASP J 1 72 ? 156.316 164.814 46.282 1.00 68.85 72 J 1
|
| 823 |
+
ATOM 543 C CB . ASP J 1 72 ? 158.398 165.005 48.825 1.00 68.85 72 J 1
|
| 824 |
+
ATOM 544 C CG . ASP J 1 72 ? 159.551 165.947 49.062 1.00 68.85 72 J 1
|
| 825 |
+
ATOM 545 O OD1 . ASP J 1 72 ? 160.691 165.462 49.183 1.00 68.85 72 J 1
|
| 826 |
+
ATOM 546 O OD2 . ASP J 1 72 ? 159.318 167.171 49.125 1.00 68.85 72 J 1
|
| 827 |
+
ATOM 547 N N . ALA J 1 73 ? 155.464 163.963 48.181 1.00 65.97 73 J 1
|
| 828 |
+
ATOM 548 C CA . ALA J 1 73 ? 154.553 163.081 47.466 1.00 65.97 73 J 1
|
| 829 |
+
ATOM 549 C C . ALA J 1 73 ? 153.501 163.878 46.715 1.00 65.97 73 J 1
|
| 830 |
+
ATOM 550 O O . ALA J 1 73 ? 153.128 163.520 45.593 1.00 65.97 73 J 1
|
| 831 |
+
ATOM 551 C CB . ALA J 1 73 ? 153.894 162.103 48.437 1.00 65.97 73 J 1
|
| 832 |
+
ATOM 552 N N . ALA J 1 74 ? 153.004 164.960 47.319 1.00 64.99 74 J 1
|
| 833 |
+
ATOM 553 C CA . ALA J 1 74 ? 152.063 165.819 46.610 1.00 64.99 74 J 1
|
| 834 |
+
ATOM 554 C C . ALA J 1 74 ? 152.700 166.405 45.358 1.00 64.99 74 J 1
|
| 835 |
+
ATOM 555 O O . ALA J 1 74 ? 152.080 166.428 44.288 1.00 64.99 74 J 1
|
| 836 |
+
ATOM 556 C CB . ALA J 1 74 ? 151.567 166.931 47.533 1.00 64.99 74 J 1
|
| 837 |
+
ATOM 557 N N . ILE J 1 75 ? 153.947 166.864 45.469 1.00 67.26 75 J 1
|
| 838 |
+
ATOM 558 C CA . ILE J 1 75 ? 154.634 167.425 44.307 1.00 67.26 75 J 1
|
| 839 |
+
ATOM 559 C C . ILE J 1 75 ? 154.797 166.367 43.222 1.00 67.26 75 J 1
|
| 840 |
+
ATOM 560 O O . ILE J 1 75 ? 154.522 166.615 42.042 1.00 67.26 75 J 1
|
| 841 |
+
ATOM 561 C CB . ILE J 1 75 ? 155.993 168.017 44.717 1.00 67.26 75 J 1
|
| 842 |
+
ATOM 562 C CG1 . ILE J 1 75 ? 155.807 169.113 45.765 1.00 67.26 75 J 1
|
| 843 |
+
ATOM 563 C CG2 . ILE J 1 75 ? 156.721 168.564 43.502 1.00 67.26 75 J 1
|
| 844 |
+
ATOM 564 C CD1 . ILE J 1 75 ? 154.983 170.274 45.286 1.00 67.26 75 J 1
|
| 845 |
+
ATOM 565 N N . ILE J 1 76 ? 155.244 165.170 43.607 1.00 71.16 76 J 1
|
| 846 |
+
ATOM 566 C CA . ILE J 1 76 ? 155.503 164.119 42.627 1.00 71.16 76 J 1
|
| 847 |
+
ATOM 567 C C . ILE J 1 76 ? 154.216 163.694 41.935 1.00 71.16 76 J 1
|
| 848 |
+
ATOM 568 O O . ILE J 1 76 ? 154.164 163.579 40.705 1.00 71.16 76 J 1
|
| 849 |
+
ATOM 569 C CB . ILE J 1 76 ? 156.205 162.925 43.299 1.00 71.16 76 J 1
|
| 850 |
+
ATOM 570 C CG1 . ILE J 1 76 ? 157.602 163.325 43.761 1.00 71.16 76 J 1
|
| 851 |
+
ATOM 571 C CG2 . ILE J 1 76 ? 156.302 161.755 42.342 1.00 71.16 76 J 1
|
| 852 |
+
ATOM 572 C CD1 . ILE J 1 76 ? 158.489 163.764 42.631 1.00 71.16 76 J 1
|
| 853 |
+
ATOM 573 N N . GLN J 1 77 ? 153.158 163.457 42.708 1.00 74.01 77 J 1
|
| 854 |
+
ATOM 574 C CA . GLN J 1 77 ? 151.870 163.093 42.139 1.00 74.01 77 J 1
|
| 855 |
+
ATOM 575 C C . GLN J 1 77 ? 151.276 164.203 41.291 1.00 74.01 77 J 1
|
| 856 |
+
ATOM 576 O O . GLN J 1 77 ? 150.522 163.917 40.355 1.00 74.01 77 J 1
|
| 857 |
+
ATOM 577 C CB . GLN J 1 77 ? 150.903 162.718 43.266 1.00 74.01 77 J 1
|
| 858 |
+
ATOM 578 C CG . GLN J 1 77 ? 149.608 162.063 42.818 1.00 74.01 77 J 1
|
| 859 |
+
ATOM 579 C CD . GLN J 1 77 ? 148.547 163.075 42.436 1.00 74.01 77 J 1
|
| 860 |
+
ATOM 580 O OE1 . GLN J 1 77 ? 148.119 163.881 43.261 1.00 74.01 77 J 1
|
| 861 |
+
ATOM 581 N NE2 . GLN J 1 77 ? 148.126 163.046 41.178 1.00 74.01 77 J 1
|
| 862 |
+
ATOM 582 N N . ASN J 1 78 ? 151.610 165.453 41.583 1.00 75.47 78 J 1
|
| 863 |
+
ATOM 583 C CA . ASN J 1 78 ? 151.007 166.584 40.903 1.00 75.47 78 J 1
|
| 864 |
+
ATOM 584 C C . ASN J 1 78 ? 151.656 166.793 39.532 1.00 75.47 78 J 1
|
| 865 |
+
ATOM 585 O O . ASN J 1 78 ? 151.100 167.503 38.692 1.00 75.47 78 J 1
|
| 866 |
+
ATOM 586 C CB . ASN J 1 78 ? 151.109 167.797 41.862 1.00 75.47 78 J 1
|
| 867 |
+
ATOM 587 C CG . ASN J 1 78 ? 150.672 169.138 41.268 1.00 75.47 78 J 1
|
| 868 |
+
ATOM 588 O OD1 . ASN J 1 78 ? 150.393 169.290 40.093 1.00 75.47 78 J 1
|
| 869 |
+
ATOM 589 N ND2 . ASN J 1 78 ? 150.555 170.120 42.149 1.00 75.47 78 J 1
|
| 870 |
+
ATOM 590 N N . PHE J 1 79 ? 152.755 166.084 39.244 1.00 76.77 79 J 1
|
| 871 |
+
ATOM 591 C CA . PHE J 1 79 ? 153.341 166.125 37.905 1.00 76.77 79 J 1
|
| 872 |
+
ATOM 592 C C . PHE J 1 79 ? 152.308 165.775 36.843 1.00 76.77 79 J 1
|
| 873 |
+
ATOM 593 O O . PHE J 1 79 ? 152.188 166.465 35.824 1.00 76.77 79 J 1
|
| 874 |
+
ATOM 594 C CB . PHE J 1 79 ? 154.513 165.146 37.794 1.00 76.77 79 J 1
|
| 875 |
+
ATOM 595 C CG . PHE J 1 79 ? 155.770 165.599 38.471 1.00 76.77 79 J 1
|
| 876 |
+
ATOM 596 C CD1 . PHE J 1 79 ? 155.885 166.866 39.000 1.00 76.77 79 J 1
|
| 877 |
+
ATOM 597 C CD2 . PHE J 1 79 ? 156.855 164.744 38.553 1.00 76.77 79 J 1
|
| 878 |
+
ATOM 598 C CE1 . PHE J 1 79 ? 157.054 167.261 39.614 1.00 76.77 79 J 1
|
| 879 |
+
ATOM 599 C CE2 . PHE J 1 79 ? 158.021 165.138 39.162 1.00 76.77 79 J 1
|
| 880 |
+
ATOM 600 C CZ . PHE J 1 79 ? 158.121 166.398 39.692 1.00 76.77 79 J 1
|
| 881 |
+
ATOM 601 N N . ARG J 1 80 ? 151.557 164.702 37.066 1.00 84.01 80 J 1
|
| 882 |
+
ATOM 602 C CA . ARG J 1 80 ? 150.552 164.246 36.118 1.00 84.01 80 J 1
|
| 883 |
+
ATOM 603 C C . ARG J 1 80 ? 149.236 164.973 36.361 1.00 84.01 80 J 1
|
| 884 |
+
ATOM 604 O O . ARG J 1 80 ? 148.856 165.220 37.506 1.00 84.01 80 J 1
|
| 885 |
+
ATOM 605 C CB . ARG J 1 80 ? 150.365 162.730 36.232 1.00 84.01 80 J 1
|
| 886 |
+
ATOM 606 C CG . ARG J 1 80 ? 149.526 162.108 35.127 1.00 84.01 80 J 1
|
| 887 |
+
ATOM 607 C CD . ARG J 1 80 ? 148.094 161.873 35.581 1.00 84.01 80 J 1
|
| 888 |
+
ATOM 608 N NE . ARG J 1 80 ? 148.029 160.982 36.733 1.00 84.01 80 J 1
|
| 889 |
+
ATOM 609 C CZ . ARG J 1 80 ? 146.964 160.838 37.510 1.00 84.01 80 J 1
|
| 890 |
+
ATOM 610 N NH1 . ARG J 1 80 ? 145.848 161.512 37.286 1.00 84.01 80 J 1
|
| 891 |
+
ATOM 611 N NH2 . ARG J 1 80 ? 147.022 159.999 38.541 1.00 84.01 80 J 1
|
| 892 |
+
ATOM 612 O OXT . ARG J 1 80 ? 148.527 165.332 35.421 1.00 84.01 80 J 1
|
| 893 |
+
#
|
flax_model/alphafold3/test_data/miniature_databases/pdb_mmcif/__init__.py
ADDED
|
File without changes
|
flax_model/alphafold3/test_data/miniature_databases/pdb_seqres_2022_09_28__subsampled_1000.fasta
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/rfam_14_4_clustered_rep_seq__subsampled_1000.fasta
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/rnacentral_active_seq_id_90_cov_80_linclust__subsampled_1000.fasta
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/uniprot_all__subsampled_1000.fasta
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/miniature_databases/uniref90__subsampled_1000.fasta
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flax_model/alphafold3/test_data/model_config.json
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"evoformer": {
|
| 3 |
+
"max_relative_chain": 2,
|
| 4 |
+
"max_relative_idx": 32,
|
| 5 |
+
"msa_channel": 64,
|
| 6 |
+
"msa_stack": {
|
| 7 |
+
"msa_attention": {
|
| 8 |
+
"num_head": 8
|
| 9 |
+
},
|
| 10 |
+
"msa_transition": {
|
| 11 |
+
"num_intermediate_factor": 4,
|
| 12 |
+
"use_glu_kernel": true
|
| 13 |
+
},
|
| 14 |
+
"num_layer": 4,
|
| 15 |
+
"outer_product_mean": {
|
| 16 |
+
"chunk_size": 128,
|
| 17 |
+
"num_outer_channel": 32
|
| 18 |
+
},
|
| 19 |
+
"pair_attention": {
|
| 20 |
+
"num_head": 4
|
| 21 |
+
},
|
| 22 |
+
"pair_transition": {
|
| 23 |
+
"num_intermediate_factor": 4,
|
| 24 |
+
"use_glu_kernel": true
|
| 25 |
+
},
|
| 26 |
+
"shard_transition_blocks": true,
|
| 27 |
+
"triangle_multiplication_incoming": {
|
| 28 |
+
"equation": "kjc,kic->ijc",
|
| 29 |
+
"use_glu_kernel": true
|
| 30 |
+
},
|
| 31 |
+
"triangle_multiplication_outgoing": {
|
| 32 |
+
"equation": "ikc,jkc->ijc",
|
| 33 |
+
"use_glu_kernel": true
|
| 34 |
+
}
|
| 35 |
+
},
|
| 36 |
+
"num_msa": 1024,
|
| 37 |
+
"pair_channel": 128,
|
| 38 |
+
"pairformer": {
|
| 39 |
+
"block_remat": false,
|
| 40 |
+
"num_layer": 48,
|
| 41 |
+
"pair_attention": {
|
| 42 |
+
"num_head": 4
|
| 43 |
+
},
|
| 44 |
+
"pair_transition": {
|
| 45 |
+
"num_intermediate_factor": 4,
|
| 46 |
+
"use_glu_kernel": true
|
| 47 |
+
},
|
| 48 |
+
"remat_block_size": 8,
|
| 49 |
+
"shard_transition_blocks": true,
|
| 50 |
+
"single_attention": {
|
| 51 |
+
"key_dim": null,
|
| 52 |
+
"num_head": 16,
|
| 53 |
+
"value_dim": null
|
| 54 |
+
},
|
| 55 |
+
"single_transition": {
|
| 56 |
+
"num_intermediate_factor": 4,
|
| 57 |
+
"use_glu_kernel": true
|
| 58 |
+
},
|
| 59 |
+
"triangle_multiplication_incoming": {
|
| 60 |
+
"equation": "kjc,kic->ijc",
|
| 61 |
+
"use_glu_kernel": true
|
| 62 |
+
},
|
| 63 |
+
"triangle_multiplication_outgoing": {
|
| 64 |
+
"equation": "ikc,jkc->ijc",
|
| 65 |
+
"use_glu_kernel": true
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"per_atom_conditioning": {
|
| 69 |
+
"atom_transformer": {
|
| 70 |
+
"attention": {
|
| 71 |
+
"key_dim": 128,
|
| 72 |
+
"num_head": 4,
|
| 73 |
+
"value_dim": 128
|
| 74 |
+
},
|
| 75 |
+
"num_blocks": 3,
|
| 76 |
+
"num_intermediate_factor": 2
|
| 77 |
+
},
|
| 78 |
+
"per_atom_channels": 128,
|
| 79 |
+
"per_atom_pair_channels": 16,
|
| 80 |
+
"per_token_channels": 384
|
| 81 |
+
},
|
| 82 |
+
"seq_channel": 384,
|
| 83 |
+
"template": {
|
| 84 |
+
"dgram_features": {
|
| 85 |
+
"max_bin": 50.75,
|
| 86 |
+
"min_bin": 3.25,
|
| 87 |
+
"num_bins": 39
|
| 88 |
+
},
|
| 89 |
+
"num_channels": 64,
|
| 90 |
+
"template_stack": {
|
| 91 |
+
"num_layer": 2,
|
| 92 |
+
"pair_attention": {
|
| 93 |
+
"num_head": 4
|
| 94 |
+
},
|
| 95 |
+
"pair_transition": {
|
| 96 |
+
"num_intermediate_factor": 2,
|
| 97 |
+
"use_glu_kernel": true
|
| 98 |
+
},
|
| 99 |
+
"shard_transition_blocks": true,
|
| 100 |
+
"single_attention": null,
|
| 101 |
+
"single_transition": null,
|
| 102 |
+
"triangle_multiplication_incoming": {
|
| 103 |
+
"equation": "kjc,kic->ijc",
|
| 104 |
+
"use_glu_kernel": true
|
| 105 |
+
},
|
| 106 |
+
"triangle_multiplication_outgoing": {
|
| 107 |
+
"equation": "ikc,jkc->ijc",
|
| 108 |
+
"use_glu_kernel": true
|
| 109 |
+
}
|
| 110 |
+
}
|
| 111 |
+
}
|
| 112 |
+
},
|
| 113 |
+
"global_config": {
|
| 114 |
+
"bfloat16": "all",
|
| 115 |
+
"final_init": "zeros",
|
| 116 |
+
"flash_attention_implementation": "triton",
|
| 117 |
+
"pair_attention_chunk_size": [
|
| 118 |
+
[
|
| 119 |
+
1536,
|
| 120 |
+
128
|
| 121 |
+
],
|
| 122 |
+
[
|
| 123 |
+
null,
|
| 124 |
+
32
|
| 125 |
+
]
|
| 126 |
+
],
|
| 127 |
+
"pair_transition_shard_spec": [
|
| 128 |
+
[
|
| 129 |
+
2048,
|
| 130 |
+
null
|
| 131 |
+
],
|
| 132 |
+
[
|
| 133 |
+
null,
|
| 134 |
+
1024
|
| 135 |
+
]
|
| 136 |
+
]
|
| 137 |
+
},
|
| 138 |
+
"heads": {
|
| 139 |
+
"confidence": {
|
| 140 |
+
"dgram_features": {
|
| 141 |
+
"max_bin": 50.75,
|
| 142 |
+
"min_bin": 3.25,
|
| 143 |
+
"num_bins": 39
|
| 144 |
+
},
|
| 145 |
+
"max_error_bin": 31.0,
|
| 146 |
+
"no_embedding_prob": 0.2,
|
| 147 |
+
"num_bins": 64,
|
| 148 |
+
"num_plddt_bins": 50,
|
| 149 |
+
"pae": {
|
| 150 |
+
"max_error_bin": 31.0,
|
| 151 |
+
"num_bins": 64
|
| 152 |
+
},
|
| 153 |
+
"pairformer": {
|
| 154 |
+
"num_layer": 4,
|
| 155 |
+
"pair_attention": {
|
| 156 |
+
"num_head": 4
|
| 157 |
+
},
|
| 158 |
+
"pair_transition": {
|
| 159 |
+
"num_intermediate_factor": 4,
|
| 160 |
+
"use_glu_kernel": true
|
| 161 |
+
},
|
| 162 |
+
"shard_transition_blocks": true,
|
| 163 |
+
"single_attention": {
|
| 164 |
+
"key_dim": null,
|
| 165 |
+
"num_head": 16,
|
| 166 |
+
"value_dim": null
|
| 167 |
+
},
|
| 168 |
+
"single_transition": {
|
| 169 |
+
"num_intermediate_factor": 4,
|
| 170 |
+
"use_glu_kernel": true
|
| 171 |
+
},
|
| 172 |
+
"triangle_multiplication_incoming": {
|
| 173 |
+
"equation": "kjc,kic->ijc",
|
| 174 |
+
"use_glu_kernel": true
|
| 175 |
+
},
|
| 176 |
+
"triangle_multiplication_outgoing": {
|
| 177 |
+
"equation": "ikc,jkc->ijc",
|
| 178 |
+
"use_glu_kernel": true
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
},
|
| 182 |
+
"diffusion": {
|
| 183 |
+
"atom_transformer": {
|
| 184 |
+
"attention": {
|
| 185 |
+
"key_dim": 128,
|
| 186 |
+
"num_head": 4,
|
| 187 |
+
"value_dim": 128
|
| 188 |
+
},
|
| 189 |
+
"num_blocks": 3,
|
| 190 |
+
"num_intermediate_factor": 2
|
| 191 |
+
},
|
| 192 |
+
"conditioning": {
|
| 193 |
+
"pair_channel": 128,
|
| 194 |
+
"prob": 0.8,
|
| 195 |
+
"seq_channel": 384
|
| 196 |
+
},
|
| 197 |
+
"eval": {
|
| 198 |
+
"gamma_0": 0.8,
|
| 199 |
+
"gamma_min": 1.0,
|
| 200 |
+
"noise_scale": 1.003,
|
| 201 |
+
"num_samples": 5,
|
| 202 |
+
"step_scale": 1.5,
|
| 203 |
+
"steps": 200
|
| 204 |
+
},
|
| 205 |
+
"eval_batch_dim_shard_size": 5,
|
| 206 |
+
"eval_batch_size": 5,
|
| 207 |
+
"per_atom_channels": 128,
|
| 208 |
+
"per_atom_pair_channels": 16,
|
| 209 |
+
"per_token_channels": 768,
|
| 210 |
+
"transformer": {
|
| 211 |
+
"attention": {
|
| 212 |
+
"key_dim": null,
|
| 213 |
+
"num_head": 16,
|
| 214 |
+
"value_dim": null
|
| 215 |
+
},
|
| 216 |
+
"block_remat": false,
|
| 217 |
+
"num_blocks": 24,
|
| 218 |
+
"num_intermediate_factor": 2,
|
| 219 |
+
"super_block_size": 4
|
| 220 |
+
}
|
| 221 |
+
},
|
| 222 |
+
"distogram": {
|
| 223 |
+
"first_break": 2.3125,
|
| 224 |
+
"last_break": 21.6875,
|
| 225 |
+
"num_bins": 64
|
| 226 |
+
}
|
| 227 |
+
},
|
| 228 |
+
"num_recycles": 10,
|
| 229 |
+
"return_distogram": false,
|
| 230 |
+
"return_embeddings": false
|
| 231 |
+
}
|
flax_model/alphafold3/version.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 DeepMind Technologies Limited
|
| 2 |
+
#
|
| 3 |
+
# AlphaFold 3 source code is licensed under CC BY-NC-SA 4.0. To view a copy of
|
| 4 |
+
# this license, visit https://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 5 |
+
#
|
| 6 |
+
# To request access to the AlphaFold 3 model parameters, follow the process set
|
| 7 |
+
# out at https://github.com/google-deepmind/alphafold3. You may only use these
|
| 8 |
+
# if received directly from Google. Use is subject to terms of use available at
|
| 9 |
+
# https://github.com/google-deepmind/alphafold3/blob/main/WEIGHTS_TERMS_OF_USE.md
|
| 10 |
+
|
| 11 |
+
"""Single source of truth for the AlphaFold version."""
|
| 12 |
+
|
| 13 |
+
__version__ = '3.0.1'
|
inputs/7r6r_data.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
inputs/t1119_search.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"dialect": "alphafold3",
|
| 3 |
+
"version": 1,
|
| 4 |
+
"name": "T1119",
|
| 5 |
+
"sequences": [
|
| 6 |
+
{
|
| 7 |
+
"protein": {
|
| 8 |
+
"id": "A",
|
| 9 |
+
"sequence": "QLEDSEVEAVAKGLEEMYANGVTEDNFKNYVKNNFAQQEISSVEEELNVNISDSCVANKIKDEFFAMISISAIVKAAQKKAWKELAVTVLRFAKANGLKTNAIIVAGQLALWAVQCG"
|
| 10 |
+
}
|
| 11 |
+
}
|
| 12 |
+
],
|
| 13 |
+
"modelSeeds": [
|
| 14 |
+
100
|
| 15 |
+
],
|
| 16 |
+
"bondedAtomPairs": null,
|
| 17 |
+
"userCCD": null
|
| 18 |
+
}
|
| 19 |
+
|
scripts/infer.sh
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 5 |
+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
export TF_CPP_MIN_LOG_LEVEL="${TF_CPP_MIN_LOG_LEVEL:-0}"
|
| 10 |
+
export XLA_PYTHON_CLIENT_MEM_FRACTION="${XLA_PYTHON_CLIENT_MEM_FRACTION:-0.95}"
|
| 11 |
+
export TRITON_ENABLE_GLOBAL_TO_LOCAL="${TRITON_ENABLE_GLOBAL_TO_LOCAL:-1}"
|
| 12 |
+
export TRITON_USE_MAKE_BLOCK_PTR="${TRITON_USE_MAKE_BLOCK_PTR:-1}"
|
| 13 |
+
export TRITON_DEFAULT_ENABLE_NUM_VGPRS512="${TRITON_DEFAULT_ENABLE_NUM_VGPRS512:-1}"
|
| 14 |
+
|
| 15 |
+
MODEL_ROOT="${ONESCIENCE_MODELS_DIR:-${PROJECT_ROOT}/weight}"
|
| 16 |
+
MODEL_DIR="${ALPHAFOLD3_MODEL_DIR:-${MODEL_ROOT}}"
|
| 17 |
+
JSON_PATH="${ALPHAFOLD3_JSON_PATH:-${PROJECT_ROOT}/inputs/7r6r_data.json}"
|
| 18 |
+
OUTPUT_DIR="${ALPHAFOLD3_OUTPUT_DIR:-${PROJECT_ROOT}/outputs}"
|
| 19 |
+
FLASH_ATTENTION="${ALPHAFOLD3_FLASH_ATTENTION:-triton}"
|
| 20 |
+
|
| 21 |
+
mkdir -p "${OUTPUT_DIR}"
|
| 22 |
+
|
| 23 |
+
python "${PROJECT_ROOT}/scripts/run_alphafold.py" \
|
| 24 |
+
--json_path="${JSON_PATH}" \
|
| 25 |
+
--model_dir="${MODEL_DIR}" \
|
| 26 |
+
--output_dir="${OUTPUT_DIR}" \
|
| 27 |
+
--run_data_pipeline=false \
|
| 28 |
+
--flash_attention_implementation="${FLASH_ATTENTION}"
|
scripts/infer_jackhmmer.sh
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 5 |
+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
export PATH="${PROJECT_ROOT}/flax_model/alphafold3/_tools/hmmer/bin:${PATH}"
|
| 9 |
+
export TF_CPP_MIN_LOG_LEVEL="${TF_CPP_MIN_LOG_LEVEL:-0}"
|
| 10 |
+
export JAX_TRACEBACK_FILTERING="${JAX_TRACEBACK_FILTERING:-off}"
|
| 11 |
+
export XLA_CLIENT_MEM_FRACTION="${XLA_CLIENT_MEM_FRACTION:-0.95}"
|
| 12 |
+
export TRITON_ENABLE_GLOBAL_TO_LOCAL="${TRITON_ENABLE_GLOBAL_TO_LOCAL:-1}"
|
| 13 |
+
export TRITON_USE_MAKE_BLOCK_PTR="${TRITON_USE_MAKE_BLOCK_PTR:-1}"
|
| 14 |
+
export TRITON_DEFAULT_ENABLE_NUM_VGPRS512="${TRITON_DEFAULT_ENABLE_NUM_VGPRS512:-1}"
|
| 15 |
+
export HIP_VISIBLE_DEVICES="${HIP_VISIBLE_DEVICES:-0}"
|
| 16 |
+
|
| 17 |
+
MODEL_ROOT="${ONESCIENCE_MODELS_DIR:-${PROJECT_ROOT}/weight}"
|
| 18 |
+
MODEL_DIR="${ALPHAFOLD3_MODEL_DIR:-${MODEL_ROOT}}"
|
| 19 |
+
DATASET_ROOT="${ALPHAFOLD3_DATASET_ROOT:-${ONESCIENCE_DATASETS_DIR:-${PROJECT_ROOT}/data}/alphafold3}"
|
| 20 |
+
DB_DIRS="${ALPHAFOLD3_DB_DIR:-${DATASET_ROOT}/public_databases}"
|
| 21 |
+
MMSEQS_DB_DIRS="${ALPHAFOLD3_MMSEQS_DB_DIR:-${DATASET_ROOT}/mmseqsDB}"
|
| 22 |
+
JSON_PATH="${ALPHAFOLD3_JSON_PATH:-${PROJECT_ROOT}/inputs/t1119_search.json}"
|
| 23 |
+
OUTPUT_DIR="${ALPHAFOLD3_OUTPUT_DIR:-${PROJECT_ROOT}/outputs}"
|
| 24 |
+
RUN_INFERENCE="${ALPHAFOLD3_RUN_INFERENCE:-false}"
|
| 25 |
+
FLASH_ATTENTION="${ALPHAFOLD3_FLASH_ATTENTION:-cutlass}"
|
| 26 |
+
|
| 27 |
+
mkdir -p "${OUTPUT_DIR}"
|
| 28 |
+
|
| 29 |
+
python "${PROJECT_ROOT}/scripts/run_alphafold.py" \
|
| 30 |
+
--json_path="${JSON_PATH}" \
|
| 31 |
+
--model_dir="${MODEL_DIR}" \
|
| 32 |
+
--output_dir="${OUTPUT_DIR}" \
|
| 33 |
+
--run_data_pipeline=true \
|
| 34 |
+
--run_inference="${RUN_INFERENCE}" \
|
| 35 |
+
--flash_attention_implementation="${FLASH_ATTENTION}" \
|
| 36 |
+
--use_mmseqs=false \
|
| 37 |
+
--use_mmseqs_gpu=false \
|
| 38 |
+
--db_dir="${DB_DIRS}" \
|
| 39 |
+
--mmseqs_db_dir="${MMSEQS_DB_DIRS}" \
|
| 40 |
+
--small_bfd_database_path="${DATASET_ROOT}/jackhmmer_split/bfd-first_non_consensus_sequences.fasta@64" \
|
| 41 |
+
--small_bfd_z_value=65928866 \
|
| 42 |
+
--mgnify_database_path="${DATASET_ROOT}/jackhmmer_split/mgy_clusters_2022_05.fa@512" \
|
| 43 |
+
--mgnify_z_value=623796864 \
|
| 44 |
+
--uniprot_cluster_annot_database_path="${DATASET_ROOT}/jackhmmer_split/uniprot_cluster_annot_2021_04.fa@256" \
|
| 45 |
+
--uniprot_cluster_annot_z_value=225619586 \
|
| 46 |
+
--uniref90_database_path="${DATASET_ROOT}/jackhmmer_split/uniref90_2022_05.fa@128" \
|
| 47 |
+
--uniref90_z_value=153742194 \
|
| 48 |
+
--jackhmmer_n_cpu="${ALPHAFOLD3_JACKHMMER_N_CPU:-2}" \
|
| 49 |
+
--jackhmmer_max_parallel_shards="${ALPHAFOLD3_JACKHMMER_MAX_PARALLEL_SHARDS:-1}" \
|
| 50 |
+
--jackhmmer_max_threads="${ALPHAFOLD3_JACKHMMER_MAX_THREADS:-8}" \
|
| 51 |
+
--nhmmer_n_cpu="${ALPHAFOLD3_NHMMER_N_CPU:-2}" \
|
| 52 |
+
--nhmmer_max_parallel_shards="${ALPHAFOLD3_NHMMER_MAX_PARALLEL_SHARDS:-1}" \
|
| 53 |
+
--nhmmer_max_threads="${ALPHAFOLD3_NHMMER_MAX_THREADS:-8}"
|
scripts/infer_mmseqs.sh
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
set -euo pipefail
|
| 3 |
+
|
| 4 |
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
| 5 |
+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
| 6 |
+
|
| 7 |
+
MODEL_ROOT="${ONESCIENCE_MODELS_DIR:-${PROJECT_ROOT}/weight}"
|
| 8 |
+
MODEL_DIR="${ALPHAFOLD3_MODEL_DIR:-${MODEL_ROOT}}"
|
| 9 |
+
MMSEQS_HOME="${ALPHAFOLD3_MMSEQS_HOME:-${MODEL_DIR}/mmseqs}"
|
| 10 |
+
export PATH="${MMSEQS_HOME}/bin:${PATH}"
|
| 11 |
+
export LD_LIBRARY_PATH="${MMSEQS_HOME}/lib:${LD_LIBRARY_PATH:-}"
|
| 12 |
+
export TF_CPP_MIN_LOG_LEVEL="${TF_CPP_MIN_LOG_LEVEL:-0}"
|
| 13 |
+
export JAX_TRACEBACK_FILTERING="${JAX_TRACEBACK_FILTERING:-off}"
|
| 14 |
+
export XLA_PYTHON_CLIENT_ALLOCATOR="${XLA_PYTHON_CLIENT_ALLOCATOR:-platform}"
|
| 15 |
+
export TRITON_ENABLE_GLOBAL_TO_LOCAL="${TRITON_ENABLE_GLOBAL_TO_LOCAL:-1}"
|
| 16 |
+
export TRITON_USE_MAKE_BLOCK_PTR="${TRITON_USE_MAKE_BLOCK_PTR:-1}"
|
| 17 |
+
export TRITON_DEFAULT_ENABLE_NUM_VGPRS512="${TRITON_DEFAULT_ENABLE_NUM_VGPRS512:-1}"
|
| 18 |
+
export HIP_VISIBLE_DEVICES="${HIP_VISIBLE_DEVICES:-0}"
|
| 19 |
+
|
| 20 |
+
DATASET_ROOT="${ALPHAFOLD3_DATASET_ROOT:-${ONESCIENCE_DATASETS_DIR:-${PROJECT_ROOT}/data}/alphafold3}"
|
| 21 |
+
DB_DIRS="${ALPHAFOLD3_DB_DIR:-${DATASET_ROOT}/public_databases}"
|
| 22 |
+
MMSEQS_DB_DIRS="${ALPHAFOLD3_MMSEQS_DB_DIR:-${DATASET_ROOT}/mmseqsDB}"
|
| 23 |
+
JSON_PATH="${ALPHAFOLD3_JSON_PATH:-${PROJECT_ROOT}/inputs/t1119_search.json}"
|
| 24 |
+
OUTPUT_DIR="${ALPHAFOLD3_OUTPUT_DIR:-${PROJECT_ROOT}/outputs}"
|
| 25 |
+
RUN_INFERENCE="${ALPHAFOLD3_RUN_INFERENCE:-false}"
|
| 26 |
+
FLASH_ATTENTION="${ALPHAFOLD3_FLASH_ATTENTION:-triton}"
|
| 27 |
+
MMSEQS_OPTIONS="${ALPHAFOLD3_MMSEQS_OPTIONS:---num-iterations 1 --db-load-mode 2 -a --max-seqs 10000 --prefilter-mode 3}"
|
| 28 |
+
|
| 29 |
+
mkdir -p "${OUTPUT_DIR}"
|
| 30 |
+
|
| 31 |
+
python "${PROJECT_ROOT}/scripts/run_alphafold.py" \
|
| 32 |
+
--json_path="${JSON_PATH}" \
|
| 33 |
+
--model_dir="${MODEL_DIR}" \
|
| 34 |
+
--output_dir="${OUTPUT_DIR}" \
|
| 35 |
+
--run_data_pipeline=true \
|
| 36 |
+
--run_inference="${RUN_INFERENCE}" \
|
| 37 |
+
--flash_attention_implementation="${FLASH_ATTENTION}" \
|
| 38 |
+
--db_dir="${DB_DIRS}" \
|
| 39 |
+
--mmseqs_db_dir="${MMSEQS_DB_DIRS}" \
|
| 40 |
+
--use_mmseqs=true \
|
| 41 |
+
--use_mmseqs_gpu=true \
|
| 42 |
+
--mmseqs_options="${MMSEQS_OPTIONS}"
|