diff --git a/openfold3/core/data/tools/colabfold_msa_server.py b/openfold3/core/data/tools/colabfold_msa_server.py index e4b12f295..ca3c84c48 100644 --- a/openfold3/core/data/tools/colabfold_msa_server.py +++ b/openfold3/core/data/tools/colabfold_msa_server.py @@ -66,6 +66,7 @@ def __str__(self) -> str: def query_colabfold_msa_server( x: list[str], + *, prefix: Path, user_agent: str, use_templates: bool = False, @@ -75,7 +76,7 @@ def query_colabfold_msa_server( use_filter: bool = True, filter: bool | None = None, host_url: str = "https://api.colabfold.com", -) -> list[str] | tuple[list[str], list[str]]: +) -> list[str] | tuple[list[str], list[str | None]]: """Submints a single query to the colabfold MSA server. Adapted from Colabfold run_mmseqs2 https://github.com/sokrypton/ColabFold/blob/main/colabfold/colabfold.py#L69 @@ -124,7 +125,7 @@ def query_colabfold_msa_server( "in the future." ) - def submit(seqs, mode, N=101): + def submit(seqs: list[str], mode: str, N: int = 101) -> dict[str, str]: n, query = N, "" for seq in seqs: query += f">{n}\n{seq}\n" @@ -159,13 +160,13 @@ def submit(seqs, mode, N=101): break try: - out = res.json() + out: dict[str, str] = res.json() except ValueError: logger.error(f"Server didn't reply with json: {res.text}") out = {"status": "ERROR"} return out - def status(ID): + def status(ID: str) -> dict[str, str]: while True: error_count = 0 try: @@ -190,13 +191,13 @@ def status(ID): continue break try: - out = res.json() + out: dict[str, str] = res.json() except ValueError: logger.error(f"Server didn't reply with json: {res.text}") out = {"status": "ERROR"} return out - def download(ID, path): + def download(ID: str, path: str) -> None: error_count = 0 while True: try: @@ -235,14 +236,14 @@ def download(ID, path): else: mode = "env-nofilter" if use_env else "nofilter" # TODO move to config construction - pairing_strategy = MsaServerPairingStrategy[pairing_strategy.upper()] + pairing_mode = MsaServerPairingStrategy[pairing_strategy.upper()] if use_pairing: use_templates = False mode = "" # greedy is default, complete was the previous behavior - if pairing_strategy == MsaServerPairingStrategy.GREEDY: + if pairing_mode == MsaServerPairingStrategy.GREEDY: mode = "pairgreedy" - elif pairing_strategy == MsaServerPairingStrategy.COMPLETE: + elif pairing_mode == MsaServerPairingStrategy.COMPLETE: mode = "paircomplete" if use_env: mode = mode + "-env" @@ -260,7 +261,9 @@ def download(ID, path): seqs_unique = [] # TODO this might be slow for large sets - see main MSA deduplication code for a # faster option - [seqs_unique.append(x) for x in seqs if x not in seqs_unique] + for s in seqs: + if s not in seqs_unique: + seqs_unique.append(s) Ms = [N + seqs_unique.index(seq) for seq in seqs] # Run query @@ -336,17 +339,16 @@ def download(ID, path): # Process templates if use_templates: - templates = {} + templates: dict[int, list[str]] = {} with open(f"{path}/pdb70.m8") as f: for line in f: p = line.rstrip().split() - M, pdb, _, _ = p[0], p[1], p[2], p[10] # M, pdb, qid, e_value - M = int(M) - if M not in templates: - templates[M] = [] - templates[M].append(pdb) + m_idx, pdb = int(p[0]), p[1] + if m_idx not in templates: + templates[m_idx] = [] + templates[m_idx].append(pdb) - template_paths = {} + template_paths_by_m: dict[int, str] = {} for k, TMPL in templates.items(): TMPL_PATH = f"{prefix}/templates_{k}" if not os.path.isdir(TMPL_PATH): @@ -386,20 +388,15 @@ def download(ID, path): os.symlink("pdb70_a3m.ffindex", f"{TMPL_PATH}/pdb70_cs219.ffindex") with open(f"{TMPL_PATH}/pdb70_cs219.ffdata", "w") as f: f.write("") - template_paths[k] = TMPL_PATH + template_paths_by_m[k] = TMPL_PATH - template_paths_ = [] - for n in Ms: - if n not in template_paths: - template_paths_.append(None) - else: - template_paths_.append(template_paths[n]) - template_paths = template_paths_ + template_paths_list: list[str | None] = [template_paths_by_m.get(n) for n in Ms] # Gather a3m lines - a3m_lines = {} + a3m_by_m: dict[int, list[str]] = {} for a3m_file in a3m_files: - update_M, M = True, None + update_M = True + current_m: int | None = None with open(a3m_file) as f: for line in f: if len(line) > 0: @@ -407,15 +404,16 @@ def download(ID, path): line = line.replace("\x00", "") update_M = True if line.startswith(">") and update_M: - M = int(line[1:].rstrip()) + current_m = int(line[1:].rstrip()) update_M = False - if M not in a3m_lines: - a3m_lines[M] = [] - a3m_lines[M].append(line) + if current_m not in a3m_by_m: + a3m_by_m[current_m] = [] + if current_m is not None: + a3m_by_m[current_m].append(line) - a3m_lines = ["".join(a3m_lines[n]) for n in Ms] + a3m_lines_out = ["".join(a3m_by_m[n]) for n in Ms] - return (a3m_lines, template_paths) if use_templates else a3m_lines + return (a3m_lines_out, template_paths_list) if use_templates else a3m_lines_out class ChainInput(NamedTuple): diff --git a/openfold3/tests/core/data/pipelines/preprocessing/test_template.py b/openfold3/tests/core/data/pipelines/preprocessing/test_template.py new file mode 100644 index 000000000..5c86fdebd --- /dev/null +++ b/openfold3/tests/core/data/pipelines/preprocessing/test_template.py @@ -0,0 +1,75 @@ +from pathlib import Path + +import openfold3 +from openfold3.core.data.io.sequence.template import ( + A3mParser, + parse_template_alignment, +) +from openfold3.core.data.io.structure.cif import _load_ciffile +from openfold3.core.data.primitives.structure.metadata import ( + get_asym_id_to_canonical_seq_dict, + get_author_to_label_chain_ids, +) + +_TEST_DATA_DIR = Path(openfold3.__file__).parent / "tests" / "test_data" + + +class TestTemplatePreprocessor: + def test_template_has_author_chain_id(self): + """Verify author->label chain ID resolution for 1RNB. + + https://github.com/aqlaboratory/openfold-3/issues/101 + + In 1RNB, author chain "A" is label chain "B" (the protein barnase). + The ColabFold alignment reports "1rnb_A" which must be resolved to + label chain "B" before the sequence can be looked up. + """ + alignment_file = ( + _TEST_DATA_DIR / "template_alignments" / "colabfold_template.m8" + ) + query_seq_str = "AQVINTFDGVADYLQTYHKLPDNYITKSEAQALGWVASKGNLADVAPGKSIGGDIFSNREGKLPGKSGRTWREADINYTSGFRNSDRILYSSDWLIYKTTDHYQTFTKIR" + templates = parse_template_alignment( + aln_path=Path(alignment_file), + query_seq_str=query_seq_str, + max_sequences=200, + ) + + # find the offending "1rnb_A" + template = templates[16] + assert template.chain_id == "A" and template.entry_id == "1rnb" + + template_structure_file = _TEST_DATA_DIR / "mmcifs" / f"{template.entry_id}.cif" + cif_file = _load_ciffile(template_structure_file) + + chain_id_seq_map = get_asym_id_to_canonical_seq_dict(cif_file) + poly_scheme = cif_file.block["pdbx_poly_seq_scheme"] + label_to_author = dict( + zip( + poly_scheme["asym_id"].as_array().tolist(), + poly_scheme["pdb_strand_id"].as_array().tolist(), + strict=True, + ) + ) + author_to_label_chain_ids = get_author_to_label_chain_ids(label_to_author) + label_chain_id = author_to_label_chain_ids[template.chain_id][0] + + # Author "A" -> label "B" (the protein chain) + assert label_chain_id == "B" + + template_sequence = chain_id_seq_map.get(label_chain_id) + + parser = A3mParser(max_sequences=None) + parsed = parser( + ( + f">query_X/1-{len(query_seq_str)}\n" + f"{query_seq_str}\n" + f">{template.entry_id}_{label_chain_id}/{1}-{len(template_sequence)}\n" + f"{template_sequence}\n" + ), + query_seq_str, + realign=True, + ) + + assert len(parsed) == 2 + assert parsed[0].seq_id == 1 + assert parsed[1].seq_id < 1 diff --git a/openfold3/tests/core/data/tools/test_colabfold_msa_server.py b/openfold3/tests/core/data/tools/test_colabfold_msa_server.py index 7b7347dcf..e953a8084 100644 --- a/openfold3/tests/core/data/tools/test_colabfold_msa_server.py +++ b/openfold3/tests/core/data/tools/test_colabfold_msa_server.py @@ -34,6 +34,7 @@ collect_colabfold_msa_data, get_sequence_hash, preprocess_colabfold_msas, + query_colabfold_msa_server, remap_colabfold_template_chain_ids, ) from openfold3.projects.of3_all_atom.config.dataset_config_components import MSASettings @@ -524,3 +525,56 @@ def test_cli_output_dir_conflict_raises(self, tmp_path): assert "Output directory mismatch" in str(exc_info.value), ( "Expected ValueError on output directory conflict" ) + + +# Barnase sequence — 1RNB author chain A = label chain B +_BARNASE_SEQ = ( + "AQVINTFDGVADYLQTYHKLPDNYITKSEAQALGWVASKGNLADVAPGKSIGGDIFSNREGKLPGK" + "SGRTWREADINYTSGFRNSDRILYSSDWLIYKTTDHYQTFTKIR" +) + + +class TestQueryColabfoldMsaServer: + """Functional test — hits real ColabFold API (~30-60s).""" + + def test_barnase_with_templates(self, tmp_path): + raw_dir = tmp_path / "raw" + a3m_lines, template_paths = query_colabfold_msa_server( + x=[_BARNASE_SEQ], + prefix=raw_dir, + user_agent="openfold-test/1.0", + use_templates=True, + use_pairing=False, + use_env=True, + use_filter=True, + ) + + # -- Returned values -- + assert len(a3m_lines) == 1 + assert a3m_lines[0].startswith(f">101\n{_BARNASE_SEQ}\n") + n_seqs = sum(1 for l in a3m_lines[0].strip().split("\n") if l.startswith(">")) + assert n_seqs > 10 # barnase is well-represented + + assert len(template_paths) == 1 + tpl_dir = Path(template_paths[0]) + assert tpl_dir.name == "templates_101" + assert tpl_dir.is_dir() + cif_files = list(tpl_dir.glob("*.cif")) + assert len(cif_files) > 0 + + # -- Files on disk -- + assert (raw_dir / "uniref.a3m").stat().st_size > 0 + assert (raw_dir / "bfd.mgnify30.metaeuk30.smag30.a3m").stat().st_size > 0 + assert (raw_dir / "out.tar.gz").exists() + + pdb70 = raw_dir / "pdb70.m8" + assert pdb70.stat().st_size > 0 + m8_lines = pdb70.read_text().strip().split("\n") + template_ids = [l.split("\t")[1] for l in m8_lines] + + # All hits should be for M-index 101 + assert all(l.split("\t")[0] == "101" for l in m8_lines) + # Template IDs are pdb_chain format + assert all("_" in tid for tid in template_ids) + # 1rnb_A must appear (the bug case — author chain A != label chain B) + assert "1rnb_A" in template_ids diff --git a/openfold3/tests/test_data/mmcifs/1rnb.cif b/openfold3/tests/test_data/mmcifs/1rnb.cif new file mode 100644 index 000000000..c80505a28 --- /dev/null +++ b/openfold3/tests/test_data/mmcifs/1rnb.cif @@ -0,0 +1,149 @@ +data_1RNB +# +_entry.id 1RNB +# +loop_ +_entity_poly.entity_id +_entity_poly.type +_entity_poly.nstd_linkage +_entity_poly.nstd_monomer +_entity_poly.pdbx_seq_one_letter_code +_entity_poly.pdbx_seq_one_letter_code_can +_entity_poly.pdbx_strand_id +_entity_poly.pdbx_target_identifier +1 polydeoxyribonucleotide no no '(DG)(DC)' GC C ? +2 'polypeptide(L)' no no +;AQVINTFDGVADYLQTYHKLPNDYITKSEAQALGWVASKGNLADVAPGKSIGGDIFSNREGKLPGKSGRTWREADINYTS +GFRNSDRILYSSDWLIYKTTDHYQTFTKIR +; +;AQVINTFDGVADYLQTYHKLPNDYITKSEAQALGWVASKGNLADVAPGKSIGGDIFSNREGKLPGKSGRTWREADINYTS +GFRNSDRILYSSDWLIYKTTDHYQTFTKIR +; +A ? +# +loop_ +_pdbx_poly_seq_scheme.asym_id +_pdbx_poly_seq_scheme.entity_id +_pdbx_poly_seq_scheme.seq_id +_pdbx_poly_seq_scheme.mon_id +_pdbx_poly_seq_scheme.ndb_seq_num +_pdbx_poly_seq_scheme.pdb_seq_num +_pdbx_poly_seq_scheme.auth_seq_num +_pdbx_poly_seq_scheme.pdb_mon_id +_pdbx_poly_seq_scheme.auth_mon_id +_pdbx_poly_seq_scheme.pdb_strand_id +_pdbx_poly_seq_scheme.pdb_ins_code +_pdbx_poly_seq_scheme.hetero +A 1 1 DG 1 111 111 DG G C . n +A 1 2 DC 2 112 112 DC C C . n +B 2 1 ALA 1 1 ? ? ? A . n +B 2 2 GLN 2 2 2 GLN GLN A . n +B 2 3 VAL 3 3 3 VAL VAL A . n +B 2 4 ILE 4 4 4 ILE ILE A . n +B 2 5 ASN 5 5 5 ASN ASN A . n +B 2 6 THR 6 6 6 THR THR A . n +B 2 7 PHE 7 7 7 PHE PHE A . n +B 2 8 ASP 8 8 8 ASP ASP A . n +B 2 9 GLY 9 9 9 GLY GLY A . n +B 2 10 VAL 10 10 10 VAL VAL A . n +B 2 11 ALA 11 11 11 ALA ALA A . n +B 2 12 ASP 12 12 12 ASP ASP A . n +B 2 13 TYR 13 13 13 TYR TYR A . n +B 2 14 LEU 14 14 14 LEU LEU A . n +B 2 15 GLN 15 15 15 GLN GLN A . n +B 2 16 THR 16 16 16 THR THR A . n +B 2 17 TYR 17 17 17 TYR TYR A . n +B 2 18 HIS 18 18 18 HIS HIS A . n +B 2 19 LYS 19 19 19 LYS LYS A . n +B 2 20 LEU 20 20 20 LEU LEU A . n +B 2 21 PRO 21 21 21 PRO PRO A . n +B 2 22 ASN 22 22 22 ASN ASN A . n +B 2 23 ASP 23 23 23 ASP ASP A . n +B 2 24 TYR 24 24 24 TYR TYR A . n +B 2 25 ILE 25 25 25 ILE ILE A . n +B 2 26 THR 26 26 26 THR THR A . n +B 2 27 LYS 27 27 27 LYS LYS A . n +B 2 28 SER 28 28 28 SER SER A . n +B 2 29 GLU 29 29 29 GLU GLU A . n +B 2 30 ALA 30 30 30 ALA ALA A . n +B 2 31 GLN 31 31 31 GLN GLN A . n +B 2 32 ALA 32 32 32 ALA ALA A . n +B 2 33 LEU 33 33 33 LEU LEU A . n +B 2 34 GLY 34 34 34 GLY GLY A . n +B 2 35 TRP 35 35 35 TRP TRP A . n +B 2 36 VAL 36 36 36 VAL VAL A . n +B 2 37 ALA 37 37 37 ALA ALA A . n +B 2 38 SER 38 38 38 SER SER A . n +B 2 39 LYS 39 39 39 LYS LYS A . n +B 2 40 GLY 40 40 40 GLY GLY A . n +B 2 41 ASN 41 41 41 ASN ASN A . n +B 2 42 LEU 42 42 42 LEU LEU A . n +B 2 43 ALA 43 43 43 ALA ALA A . n +B 2 44 ASP 44 44 44 ASP ASP A . n +B 2 45 VAL 45 45 45 VAL VAL A . n +B 2 46 ALA 46 46 46 ALA ALA A . n +B 2 47 PRO 47 47 47 PRO PRO A . n +B 2 48 GLY 48 48 48 GLY GLY A . n +B 2 49 LYS 49 49 49 LYS LYS A . n +B 2 50 SER 50 50 50 SER SER A . n +B 2 51 ILE 51 51 51 ILE ILE A . n +B 2 52 GLY 52 52 52 GLY GLY A . n +B 2 53 GLY 53 53 53 GLY GLY A . n +B 2 54 ASP 54 54 54 ASP ASP A . n +B 2 55 ILE 55 55 55 ILE ILE A . n +B 2 56 PHE 56 56 56 PHE PHE A . n +B 2 57 SER 57 57 57 SER SER A . n +B 2 58 ASN 58 58 58 ASN ASN A . n +B 2 59 ARG 59 59 59 ARG ARG A . n +B 2 60 GLU 60 60 60 GLU GLU A . n +B 2 61 GLY 61 61 61 GLY GLY A . n +B 2 62 LYS 62 62 62 LYS LYS A . n +B 2 63 LEU 63 63 63 LEU LEU A . n +B 2 64 PRO 64 64 64 PRO PRO A . n +B 2 65 GLY 65 65 65 GLY GLY A . n +B 2 66 LYS 66 66 66 LYS LYS A . n +B 2 67 SER 67 67 67 SER SER A . n +B 2 68 GLY 68 68 68 GLY GLY A . n +B 2 69 ARG 69 69 69 ARG ARG A . n +B 2 70 THR 70 70 70 THR THR A . n +B 2 71 TRP 71 71 71 TRP TRP A . n +B 2 72 ARG 72 72 72 ARG ARG A . n +B 2 73 GLU 73 73 73 GLU GLU A . n +B 2 74 ALA 74 74 74 ALA ALA A . n +B 2 75 ASP 75 75 75 ASP ASP A . n +B 2 76 ILE 76 76 76 ILE ILE A . n +B 2 77 ASN 77 77 77 ASN ASN A . n +B 2 78 TYR 78 78 78 TYR TYR A . n +B 2 79 THR 79 79 79 THR THR A . n +B 2 80 SER 80 80 80 SER SER A . n +B 2 81 GLY 81 81 81 GLY GLY A . n +B 2 82 PHE 82 82 82 PHE PHE A . n +B 2 83 ARG 83 83 83 ARG ARG A . n +B 2 84 ASN 84 84 84 ASN ASN A . n +B 2 85 SER 85 85 85 SER SER A . n +B 2 86 ASP 86 86 86 ASP ASP A . n +B 2 87 ARG 87 87 87 ARG ARG A . n +B 2 88 ILE 88 88 88 ILE ILE A . n +B 2 89 LEU 89 89 89 LEU LEU A . n +B 2 90 TYR 90 90 90 TYR TYR A . n +B 2 91 SER 91 91 91 SER SER A . n +B 2 92 SER 92 92 92 SER SER A . n +B 2 93 ASP 93 93 93 ASP ASP A . n +B 2 94 TRP 94 94 94 TRP TRP A . n +B 2 95 LEU 95 95 95 LEU LEU A . n +B 2 96 ILE 96 96 96 ILE ILE A . n +B 2 97 TYR 97 97 97 TYR TYR A . n +B 2 98 LYS 98 98 98 LYS LYS A . n +B 2 99 THR 99 99 99 THR THR A . n +B 2 100 THR 100 100 100 THR THR A . n +B 2 101 ASP 101 101 101 ASP ASP A . n +B 2 102 HIS 102 102 102 HIS HIS A . n +B 2 103 TYR 103 103 103 TYR TYR A . n +B 2 104 GLN 104 104 104 GLN GLN A . n +B 2 105 THR 105 105 105 THR THR A . n +B 2 106 PHE 106 106 106 PHE PHE A . n +B 2 107 THR 107 107 107 THR THR A . n +B 2 108 LYS 108 108 108 LYS LYS A . n +B 2 109 ILE 109 109 109 ILE ILE A . n +B 2 110 ARG 110 110 110 ARG ARG A . n +# diff --git a/openfold3/tests/test_data/template_alignments/colabfold_template.m8 b/openfold3/tests/test_data/template_alignments/colabfold_template.m8 new file mode 100644 index 000000000..84926f9e8 --- /dev/null +++ b/openfold3/tests/test_data/template_alignments/colabfold_template.m8 @@ -0,0 +1,62 @@ +101 1b27_B 1.0 110 0 0 1 110 1 110 1.022e-45 160 110M +101 6pqk_A 0.981 108 2 0 3 110 1 108 2.6399999999999998e-45 159 108M +101 1bse_C 0.99 108 1 0 3 110 1 108 4.9679999999999996e-45 158 108M +101 1b2s_C 0.99 110 1 0 1 110 1 110 6.815e-45 158 110M +101 1bsb_C 0.99 108 1 0 3 110 1 108 9.349999999999999e-45 158 108M +101 1x1y_B 0.99 110 1 0 1 110 1 110 9.349999999999999e-45 158 110M +101 2za4_A 0.99 108 1 0 3 110 1 108 1.76e-44 157 108M +101 1ban_B 0.99 108 1 0 3 110 1 108 3.3119999999999996e-44 156 108M +101 1b20_B 0.99 108 1 0 3 110 1 108 3.3119999999999996e-44 156 108M +101 1buj_A 0.842 108 17 0 3 110 2 109 3.3119999999999996e-44 156 108M +101 1bsd_C 0.99 107 1 0 4 110 1 107 4.544e-44 156 107M +101 1brg_C 0.99 108 1 0 3 110 1 108 4.544e-44 156 108M +101 1brk_C 0.99 107 1 0 4 110 1 107 6.233e-44 155 107M +101 1bsa_C 0.99 107 1 0 4 110 1 107 6.233e-44 155 107M +101 1b2z_C 0.99 107 1 0 4 110 1 107 8.552e-44 155 107M +101 1b21_B 0.981 108 2 0 3 110 1 108 8.552e-44 155 108M +101 1rnb_A 0.981 109 2 0 2 110 1 109 8.552e-44 155 109M +101 1bsc_B 0.99 107 1 0 4 110 1 107 1.173e-43 154 107M +101 1bao_C 0.99 107 1 0 4 110 1 107 1.173e-43 154 107M +101 1brj_C 0.99 108 1 0 3 110 1 108 1.173e-43 154 108M +101 1brh_C 0.99 108 1 0 3 110 1 108 1.173e-43 154 108M +101 4haa_D 0.833 108 18 0 3 110 2 109 1.173e-43 154 108M +101 1bri_C 0.99 107 1 0 4 110 1 107 1.61e-43 154 107M +101 1bns_C 0.99 107 1 0 4 110 1 107 2.208e-43 154 107M +101 1bnf_A 0.981 108 2 0 3 110 1 108 4.156e-43 153 108M +101 2rbi_B 0.833 108 18 0 3 110 1 108 5.701e-43 153 108M +101 2kf3_A 0.99 108 1 0 3 110 1 108 5.701e-43 153 108M +101 2c4b_B 0.99 108 1 0 3 110 1 108 5.701e-43 153 108M +101 1bng_C 0.981 107 2 0 4 110 1 107 5.2150000000000006e-42 150 107M +101 3q3f_A 0.936 110 7 0 1 110 1 110 5.2150000000000006e-42 150 110M +101 1goy_B 0.796 108 22 0 3 110 1 108 7.155e-42 149 108M +101 3da7_A 1.0 66 0 0 1 66 44 109 4.0910000000000004e-25 101 66M +101 3da7_E 1.0 60 0 0 7 66 44 103 2.286e-22 93 60M +101 3da7_B 1.0 57 0 0 8 64 44 100 1.525e-21 91 57M +101 3da7_G 0.892 65 7 0 2 66 38 102 1.525e-21 91 65M +101 3d5g_C 0.31 58 39 1 53 109 35 92 5.437e-14 69 30M1D27M +101 1mgr_A 0.322 59 38 2 53 109 35 93 7.458e-14 69 30M1D11M1D16M +101 3dgy_C 0.35 57 36 1 53 109 32 87 1.023e-13 68 24M1I32M +101 3dgy_A 0.35 57 36 1 53 109 33 88 1.023e-13 68 24M1I32M +101 3d5i_C 0.315 57 37 1 53 109 32 86 4.964e-13 66 27M2I28M +101 3d4a_C 0.315 57 36 1 53 109 32 85 6.808e-13 66 27M3I27M +101 4j5g_B 0.338 59 37 2 53 109 34 92 9.337e-13 66 30M1D9M1D18M +101 1ay7_A 0.338 59 37 2 53 109 34 92 9.337e-13 66 30M1D9M1D18M +101 1ynv_X 0.338 59 37 2 53 109 34 92 9.337e-13 66 30M1D9M1D18M +101 1c54_A 0.338 59 37 2 53 109 34 92 9.337e-13 66 30M1D9M1D18M +101 1uci_B 0.338 59 37 2 53 109 34 92 9.337e-13 66 30M1D9M1D18M +101 4gho_B 0.338 59 37 2 53 109 34 92 9.337e-13 66 30M1D9M1D18M +101 4j5g_A 0.338 59 37 2 53 109 34 92 9.337e-13 66 30M1D9M1D18M +101 1rsn_A 0.338 59 37 2 53 109 34 92 1.281e-12 65 30M1D9M1D18M +101 1ucj_B 0.338 59 37 2 53 109 34 92 1.281e-12 65 30M1D9M1D18M +101 1t2i_A 0.338 59 37 2 53 109 34 92 1.756e-12 65 30M1D11M1D16M +101 1uck_B 0.338 59 37 2 53 109 34 92 1.756e-12 65 30M1D9M1D18M +101 4j5k_A 0.338 59 37 2 53 109 34 92 3.303e-12 64 30M1D9M1D18M +101 4j5k_B 0.338 59 37 2 53 109 34 92 3.303e-12 64 30M1D9M1D18M +101 1i8v_B 0.322 59 38 2 53 109 34 92 4.529e-12 64 30M1D9M1D18M +101 3a5e_A 0.322 59 38 2 53 109 34 92 4.529e-12 64 30M1D9M1D18M +101 1t2h_B 0.338 59 37 2 53 109 34 92 6.211e-12 63 30M1D9M1D18M +101 1box_A 0.322 59 38 2 53 109 33 91 8.517e-12 63 30M1D9M1D18M +101 1i70_B 0.322 59 38 2 53 109 34 92 8.517e-12 63 30M1D9M1D18M +101 1ucl_B 0.355 59 36 2 53 109 34 92 8.517e-12 63 22M1D17M1D18M +101 1zgx_A 0.321 28 19 0 53 80 34 61 0.002519 38 28M +101 1zgx_B 0.392 28 16 1 83 109 2 29 0.01637 36 9M1D18M