Skip to content

Commit b271852

Browse files
committed
Metadynamics morph, align_together, bugfixes
1 parent 0f4d028 commit b271852

15 files changed

Lines changed: 65330 additions & 57 deletions

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ A utility to automatically prepare structures from the PDB for molecular dynamic
77
* [X] Automatically download structures, sequences and metadata from the PDB and UNIPROT
88
* [X] Automatically fill missing loops with modeller
99
* [X] Automatically add missing atoms and fix non-standard residues with pdbfixer
10-
* [X] Automatically propagate metadata through to finalised structure files
10+
* [ ] Automatically propagate metadata through to finalised structure files
1111
* [X] Automatically resolve steric clashes and minimise structures
12+
* [X] Automatically trim together structures to be the same length
1213
* [X] Run simple MD simulations for testing, validation and minimisation
13-
* [ ] Create 'morph' trajectories with metadynamics
14+
* [X] Create 'morph' trajectories with metadynamics
1415
* [ ] AIIDA integration
1516

1617
## Installation
@@ -35,9 +36,11 @@ A utility to automatically prepare structures from the PDB for molecular dynamic
3536
* If you already have a minimised structure, you can skip minimisation: `runmd structure.cif --traj_out traj.xtc --md_steps 5000 --step 100 -nomin -notest`
3637
* Solvate the simulation box: `runmd structure.cif -o structure_minimised.cif --traj_out traj.xtc --md_steps 500 --step 10 -solv tip4pew`. tip3p, tip4pew and spce are supported. You can also add pressure coupling with `--pressure 1.0` (for 1 bar)
3738
* Run with different force fields: `runmd structure.cif -o structure_minimised.cif --traj_out traj.xtc --md_steps 500 --step 50 -ff amber14` runs with amber14. AMOEBA is also available, and amber19 is available if you have a recent version of OpenMM.
38-
* Finally, you may wish to fix the backbone in place and just equilibrate the side chains: `runmd structure.cif -o structure_minimised.cif --fix_backbone -solv tip4pew --notest`
39+
* Fix the backbone in place and just equilibrate the side chains: `runmd structure.cif -o structure_minimised.cif --fix_backbone -solv tip4pew --notest`
40+
* Use metadynamics to create a (non-physical!) guided md morph trajectory between two structures: `runmd pre.cif -m post.cif -o minimised_out.pdb`
41+
* Note: if you have two files for the same structure which aren't aligned (e.g. they have slightly different starting/ending residues), you can trim the ends to align them: `aligntogether pre.cif post.cif pre_cropped.cif post_cropped.cif`
3942
* Use `runmd --help` for a full list of parameters.
4043

4144
## License
4245

43-
None, yet
46+
AGPLv3

prepmd/AAAA.seq

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
>P1;AAAA
3+
structureX:AAAA:1:A:+1054:B:::-1.00:-1.00
4+
MHHHHHHAAACERALQYKLGDKIHGFTVNQVTSVPELFLTAVKLTHDDTGARYLHLAREDTNNLFSVQFRTTPMD
5+
STGVPHILEHTVLCGSQKYPCRDPFFKMLNRSLSTFMNAFTASDYTLYPFSTQNPKDFQNLLSVYLDATFFPCLR
6+
ELDFWQEGWRLEHENPSDPQTPLVFKGVVFNEMKGAFTDNERIFSQHLQNRLLPDHTYSVVSGGDPLCIPELTWE
7+
QLKQFHATHYHPSNARFFTYGNFPLEQHLKQIHEEALSKFQKIEPSTVVPAQTPWDKPREFQITCGPDSFATDPS
8+
KQTTVSVSFLLPDITDTFEAFTLSLLSSLLTSGPNSPFYKALIESGLGTDFSPDVGYNGYTREAYFSVGLQGIVE
9+
KDIETVRSLIDRTIDEVVEKGFEDDRIEALLHKIEIQMKHQSTSFGLMLTSYIASCWNHDGDPVELLKLGNQLAK
10+
FRQCLQENPKFLQEKVKQYFKNNQHKLTLSMRPDDKYHEKQAQVEATKLKQKVEALSPGDRQQIYEKGLELRSQQ
11+
SKPQDASCLPALKVSDIEPTIPVTELDVVLTAGDIPVQYCAQPTNGMVYFRAFSSLNTLPEELRPYVPLFCSVLT
12+
KLGCGLLDYREQAQQIELKTGGMSASPHVLPDDSHMDTYEQGVLFSSLCLDRNLPDMMQLWSEIFNNPCFEEEEH
13+
FKVLVKMTAQELANGIPDSGHLYASIRAGRTLTPAGDLQETFSGMDQVRLMKRIAEMTDIKPILRKLPRIKKHLL
14+
NGDNMRCSVNATPQQMPQTEKAVEDFLRSIGRSKKERRPVRPHTVEKPVPSSSGGDAHVPHGSQVIRKLVMEPTF
15+
KPWQMKTHFLMPFPVNYVGECIRTVPYTDPDHASLKILARLMTAKFLHTEIREKGGAYGGGAKLSHNGIFTLYSY
16+
RDPNTIETLQSFGKAVDWAKSGKFTQQDIDEAKLSVFSTVDAPVAPSDKGMDHFLYGLSDEMKQAHREQLFAVSH
17+
DKLLAVSDRYLGTGKSTHGLAILGPENPKIAKDPSWIIR/DAEFRHDSGYEVHHQKLVFFAEDVGSNKGAIIGLM
18+
VGGVV*

prepmd/BBBB.seq

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
>P1;BBBB
3+
structureX:BBBB:1:A:+1014:A:::-1.00:-1.00
4+
MHHHHHHAAACERALQYKLGDKIHGFTVNQVTSVPELFLTAVKLTHDDTGARYLHLAREDTNNLFSVQFRTTPMD
5+
STGVPHILEHTVLCGSQKYPCRDPFFKMLNRSLSTFMNAFTASDYTLYPFSTQNPKDFQNLLSVYLDATFFPCLR
6+
ELDFWQEGWRLEHENPSDPQTPLVFKGVVFNEMKGAFTDNERIFSQHLQNRLLPDHTYSVVSGGDPLCIPELTWE
7+
QLKQFHATHYHPSNARFFTYGNFPLEQHLKQIHEEALSKFQKIEPSTVVPAQTPWDKPREFQITCGPDSFATDPS
8+
KQTTVSVSFLLPDITDTFEAFTLSLLSSLLTSGPNSPFYKALIESGLGTDFSPDVGYNGYTREAYFSVGLQGIVE
9+
KDIETVRSLIDRTIDEVVEKGFEDDRIEALLHKIEIQMKHQSTSFGLMLTSYIASCWNHDGDPVELLKLGNQLAK
10+
FRQCLQENPKFLQEKVKQYFKNNQHKLTLSMRPDDKYHEKQAQVEATKLKQKVEALSPGDRQQIYEKGLELRSQQ
11+
SKPQDASCLPALKVSDIEPTIPVTELDVVLTAGDIPVQYCAQPTNGMVYFRAFSSLNTLPEELRPYVPLFCSVLT
12+
KLGCGLLDYREQAQQIELKTGGMSASPHVLPDDSHMDTYEQGVLFSSLCLDRNLPDMMQLWSEIFNNPCFEEEEH
13+
FKVLVKMTAQELANGIPDSGHLYASIRAGRTLTPAGDLQETFSGMDQVRLMKRIAEMTDIKPILRKLPRIKKHLL
14+
NGDNMRCSVNATPQQMPQTEKAVEDFLRSIGRSKKERRPVRPHTVEKPVPSSSGGDAHVPHGSQVIRKLVMEPTF
15+
KPWQMKTHFLMPFPVNYVGECIRTVPYTDPDHASLKILARLMTAKFLHTEIREKGGAYGGGAKLSHNGIFTLYSY
16+
RDPNTIETLQSFGKAVDWAKSGKFTQQDIDEAKLSVFSTVDAPVAPSDKGMDHFLYGLSDEMKQAHREQLFAVSH
17+
DKLLAVSDRYLGTGKSTHGLAILGPENPKIAKDPSWIIR*

prepmd/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55
from . import util
66
from . import prep
77
from . import model
8+
from . import metadynamics
9+
from . import align_together
810
from . import add_modeller_license
9-
__version__ = "0.3"
11+
__version__ = "1.0"

prepmd/align_together.py

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""
4+
Trim the ends off two PDB files until their indices match.
5+
Note: this is a big pile of spaghetti, it turns out doing this in a robust way
6+
is actually kind of difficult. For example, I went to all the effort of getting
7+
positions of residues relative to the start and end of each chain, rather than
8+
measuring them from the start, only to discover that Bio.PDB throws weird
9+
errors when you do for element in reversed(object).
10+
"""
11+
12+
from Bio.PDB.PDBParser import PDBParser
13+
from Bio.PDB.MMCIFParser import MMCIFParser
14+
15+
#from Bio.PDB import StructureAlignment
16+
import Bio.PDB
17+
from Bio.PDB.mmcifio import MMCIFIO
18+
import modeller
19+
from prepmd import get_residues, model
20+
import argparse
21+
# from Bio import Align
22+
23+
"""
24+
def align_biopython(s1, s2):
25+
26+
p = PDBParser(QUIET=1)
27+
28+
s1 = p.get_structure("1", s1)
29+
s2 = p.get_structure("2", s2)
30+
31+
model_1 = s1[0]
32+
33+
model_2 = s2[0]
34+
35+
alignment = StructureAlignment(m1=model_1, m2=model_2)
36+
37+
return alignment
38+
"""
39+
40+
def align_modeller(s1, s2, code1="AAAA", code2="BBBB", outfile="alignment.out"):
41+
print("Getting missing residues from input file...")
42+
pdb1_res = get_residues.get_residues_pdb(s1, code1)
43+
pdb2_res = get_residues.get_residues_pdb(s2, code2)
44+
# pdb_fullseq = prepmd.get_residues.get_fullseq_pdb(inmodel, code)
45+
with open(code1+".seq", "w") as file:
46+
file.write("".join(pdb1_res))
47+
with open(code2+".seq", "w") as file:
48+
file.write("".join(pdb2_res))
49+
env = modeller.environ()
50+
print("Aligning sequences...")
51+
aln = modeller.Alignment(env)
52+
aln.append(file=code1+".seq", align_codes=code1)
53+
aln.append(file=code2+".seq", align_codes=code2)
54+
aln.salign()
55+
print("Succesfully aligned.", end="")
56+
aln.write(file=outfile)
57+
58+
59+
# given an anlignment fasta, create an index of which sequences have gaps in which places
60+
def get_gaps(alignment_fasta_path):
61+
alignment_fasta = model.fasta(alignment_fasta_path)
62+
sequence1 = "".join(alignment_fasta[0][1])
63+
sequence2 = "".join(alignment_fasta[1][1])
64+
sequence1 = sequence1.replace("*", "").replace("/", "") # no asterisk
65+
sequence2 = sequence2.replace("*", "").replace("/", "") # no asterisk
66+
gaps = ""
67+
for res1, res2 in zip(sequence1, sequence2):
68+
if res1 == "-" and res2 == "-":
69+
gaps += "G"
70+
if res1 == "-" and res2 != "-":
71+
gaps += "1"
72+
if res1 != "-" and res2 == "-":
73+
gaps += "2"
74+
else:
75+
gaps += "S"
76+
return gaps
77+
78+
79+
def print_mask(mask):
80+
for i in mask:
81+
if i:
82+
print("O", end="")
83+
else:
84+
print("X", end="")
85+
print("")
86+
87+
88+
def mark_missing_ends(gaps):
89+
dseq1 = False
90+
dseq2 = False
91+
missing_seq1 = []
92+
missing_seq2 = []
93+
for i in gaps:
94+
if i == "1":
95+
dseq1 = True
96+
if i == "2":
97+
dseq2 = True
98+
if i == "G":
99+
dseq1 = True
100+
dseq2 = True
101+
missing_seq1.append(dseq1)
102+
missing_seq2.append(dseq2)
103+
return missing_seq1, missing_seq2
104+
105+
106+
# Find the innermost gap at each end at mark anything further than that gap for deletion
107+
def mark_innermost_gap(gaps):
108+
109+
gaps_half1 = gaps[:len(gaps)//2]
110+
gaps_half2 = gaps[len(gaps)//2:]
111+
112+
delete_half1_seq1, delete_half1_seq2 = mark_missing_ends(
113+
''.join(reversed(gaps_half1)))
114+
115+
delete_half1_seq1.reverse()
116+
delete_half1_seq2.reverse()
117+
118+
delete_half2_seq1, delete_half2_seq2 = mark_missing_ends(gaps_half2)
119+
120+
missing_seq1 = delete_half1_seq1 + delete_half2_seq1
121+
missing_seq2 = delete_half1_seq2 + delete_half2_seq2
122+
123+
return missing_seq1, missing_seq2
124+
125+
# get the exact number of residues at each end to be deleted
126+
def get_ends_deletion(missing_seq):
127+
delete_start = None
128+
delete_end = None
129+
130+
prev_res = True
131+
if missing_seq[0] != False:
132+
for res in range(len(missing_seq)):
133+
if missing_seq[res] != prev_res:
134+
delete_start = res # indexing/ob1 error!
135+
break
136+
prev_res = missing_seq[res]
137+
delete_no_start = delete_start
138+
139+
prev_res = True
140+
if missing_seq[-1] != False:
141+
for res in reversed(range(len(missing_seq))):
142+
if missing_seq[res] != prev_res:
143+
delete_end = res+1 # indexing/ob1 error!
144+
break
145+
prev_res = missing_seq[res]
146+
if type(delete_end) == int:
147+
delete_no_end = len(missing_seq) - delete_end
148+
else:
149+
delete_no_end = None
150+
return delete_no_start, delete_no_end
151+
152+
153+
def remove_from_model(structure, number_start, number_end, verbose=True):
154+
# you need to build this index because the biopython objects don't let you
155+
# iterate through them backwards or do anything with the loop variables
156+
models = []
157+
for model in structure:
158+
chains = []
159+
for chain in model:
160+
residues = []
161+
for residue in chain:
162+
residues.append(residue.id)
163+
chains.append(residues)
164+
models.append(chains)
165+
166+
number_removed = 0
167+
to_remove = []
168+
if number_end:
169+
for model_idx, model in zip(reversed(range(len(models))), reversed(models)):
170+
for chain_idx, chain in zip(reversed(range(len(model))), reversed(model)):
171+
for residue in reversed(chain):
172+
if number_removed < number_end:
173+
to_remove.append((model_idx, chain_idx, residue))
174+
number_removed += 1
175+
176+
if number_start:
177+
number_removed = 0
178+
for model_idx, model in zip(range(len(models)), models):
179+
for chain_idx, chain in zip(range(len(model)), model):
180+
for residue in chain:
181+
if number_removed < number_start:
182+
to_remove.append((model_idx, chain_idx, residue))
183+
number_removed += 1
184+
185+
for model, chain, res in to_remove:
186+
curr_chain = structure[model].child_list[chain]
187+
curr_chain.detach_child(res)
188+
189+
print("Removed "+str(len(to_remove))+" residues.")
190+
191+
return structure
192+
193+
def align_together(seq1path, seq2path, seq1out, seq2out,
194+
code1="AAAA", code2="BBBB", verbose=True):
195+
196+
align_modeller(seq1path, seq2path, outfile="alignment.out")
197+
gaps = get_gaps("alignment.out")
198+
199+
if verbose:
200+
print("GAPS:")
201+
print(gaps)
202+
print("")
203+
204+
missing_seq1, missing_seq2 = mark_innermost_gap(gaps)
205+
206+
if verbose:
207+
print("Missing in sequence 1:")
208+
print_mask(missing_seq1)
209+
print("")
210+
print("Missing in sequence 2:")
211+
print_mask(missing_seq2)
212+
213+
seq2_delete_start, seq2_delete_end = get_ends_deletion(missing_seq1)
214+
seq1_delete_start, seq1_delete_end = get_ends_deletion(missing_seq2)
215+
216+
if verbose:
217+
print("Delete in sequence 1: "+str([seq1_delete_start,seq1_delete_end]))
218+
print("Delete in sequence 2: "+str([seq2_delete_start,seq2_delete_end]))
219+
220+
if ".pdb" in seq1path and ".pdb" in seq2path:
221+
parser = PDBParser(PERMISSIVE=1)
222+
if ".mmcif" in seq1path+seq2path or ".mmCif" in seq1path+seq2path:
223+
parser = MMCIFParser(PERMISSIVE=1)
224+
seq1_structure = parser.get_structure(code1, seq1path)
225+
seq2_structure = parser.get_structure(code2, seq2path)
226+
227+
if verbose:
228+
print("SEQ1 residues: "+str(len(list(seq1_structure.get_residues()))))
229+
print("SEQ2 residues: "+str(len(list(seq2_structure.get_residues()))))
230+
231+
seq1_structure = remove_from_model(
232+
seq1_structure, seq1_delete_start, seq1_delete_end, verbose=True)
233+
seq2_structure = remove_from_model(
234+
seq2_structure, seq2_delete_start, seq2_delete_end, verbose=True)
235+
236+
seq1_length = len(list(seq1_structure.get_residues()))
237+
seq2_length = len(list(seq2_structure.get_residues()))
238+
239+
if verbose:
240+
print("SEQ1 residues: "+str(seq1_length))
241+
print("SEQ2 residues: "+str(seq2_length))
242+
243+
if seq1_length != seq2_length:
244+
raise ValueError("The modified structures still don't have the same"
245+
" length.")
246+
247+
if ".mmcif" in seq1path+seq2path or ".mmCif" in seq1path+seq2path:
248+
io = MMCIFIO()
249+
if ".pdb" in seq1path and ".pdb" in seq2path:
250+
io = Bio.PDB.PDBIO()
251+
252+
io.set_structure(seq1_structure)
253+
io.save(seq1out)
254+
io.set_structure(seq2_structure)
255+
io.save(seq2out)
256+
257+
258+
def entry_point():
259+
"CLI entry point function. Uses sys.argv and argparse args object."
260+
261+
parser = argparse.ArgumentParser(prog="aligntogether",
262+
description="Trim two structure files so "
263+
"that they are aligned and are the same "
264+
"length.")
265+
parser.add_argument("struct1in", help="Path to first input structure")
266+
parser.add_argument("struct2in", help="Path to second input structure")
267+
parser.add_argument("struct1out", help="Path to first output structure")
268+
parser.add_argument("struct2out", help="Path to second output structure")
269+
parser.add_argument(
270+
"-c1", "--code1", help="PDB code for file 1 (only used as a label)",
271+
default="AAAA")
272+
parser.add_argument(
273+
"-c2", "--code2", help="PDB code for file 2 (only used as a label)",
274+
default="BBBB")
275+
276+
args = parser.parse_args()
277+
align_together(args.struct1in,
278+
args.struct2in,
279+
args.struct1out,
280+
args.struct2out,
281+
args.c1,
282+
args.c2)
283+
284+
if __name__ == "__main__":
285+
entry_point()

prepmd/alignment.out

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
>P1;AAAA
3+
structureX:AAAA:1:A:+1054:B:::-1.00:-1.00
4+
MHHHHHHAAACERALQYKLGDKIHGFTVNQVTSVPELFLTAVKLTHDDTGARYLHLAREDTNNLFSVQFRTTPMD
5+
STGVPHILEHTVLCGSQKYPCRDPFFKMLNRSLSTFMNAFTASDYTLYPFSTQNPKDFQNLLSVYLDATFFPCLR
6+
ELDFWQEGWRLEHENPSDPQTPLVFKGVVFNEMKGAFTDNERIFSQHLQNRLLPDHTYSVVSGGDPLCIPELTWE
7+
QLKQFHATHYHPSNARFFTYGNFPLEQHLKQIHEEALSKFQKIEPSTVVPAQTPWDKPREFQITCGPDSFATDPS
8+
KQTTVSVSFLLPDITDTFEAFTLSLLSSLLTSGPNSPFYKALIESGLGTDFSPDVGYNGYTREAYFSVGLQGIVE
9+
KDIETVRSLIDRTIDEVVEKGFEDDRIEALLHKIEIQMKHQSTSFGLMLTSYIASCWNHDGDPVELLKLGNQLAK
10+
FRQCLQENPKFLQEKVKQYFKNNQHKLTLSMRPDDKYHEKQAQVEATKLKQKVEALSPGDRQQIYEKGLELRSQQ
11+
SKPQDASCLPALKVSDIEPTIPVTELDVVLTAGDIPVQYCAQPTNGMVYFRAFSSLNTLPEELRPYVPLFCSVLT
12+
KLGCGLLDYREQAQQIELKTGGMSASPHVLPDDSHMDTYEQGVLFSSLCLDRNLPDMMQLWSEIFNNPCFEEEEH
13+
FKVLVKMTAQELANGIPDSGHLYASIRAGRTLTPAGDLQETFSGMDQVRLMKRIAEMTDIKPILRKLPRIKKHLL
14+
NGDNMRCSVNATPQQMPQTEKAVEDFLRSIGRSKKERRPVRPHTVEKPVPSSSGGDAHVPHGSQVIRKLVMEPTF
15+
KPWQMKTHFLMPFPVNYVGECIRTVPYTDPDHASLKILARLMTAKFLHTEIREKGGAYGGGAKLSHNGIFTLYSY
16+
RDPNTIETLQSFGKAVDWAKSGKFTQQDIDEAKLSVFSTVDAPVAPSDKGMDHFLYGLSDEMKQAHREQLFAVSH
17+
DKLLAVSDRYLGTGKSTHGLAILGPENPKIAKDPSWIIR/DAEFRHDSGYEVHHQKLVFFAEDVGSNKGAIIGLM
18+
VGGVV*
19+
20+
>P1;BBBB
21+
structureX:BBBB:1:A:+1014:A:::-1.00:-1.00
22+
MHHHHHHAAACERALQYKLGDKIHGFTVNQVTSVPELFLTAVKLTHDDTGARYLHLAREDTNNLFSVQFRTTPMD
23+
STGVPHILEHTVLCGSQKYPCRDPFFKMLNRSLSTFMNAFTASDYTLYPFSTQNPKDFQNLLSVYLDATFFPCLR
24+
ELDFWQEGWRLEHENPSDPQTPLVFKGVVFNEMKGAFTDNERIFSQHLQNRLLPDHTYSVVSGGDPLCIPELTWE
25+
QLKQFHATHYHPSNARFFTYGNFPLEQHLKQIHEEALSKFQKIEPSTVVPAQTPWDKPREFQITCGPDSFATDPS
26+
KQTTVSVSFLLPDITDTFEAFTLSLLSSLLTSGPNSPFYKALIESGLGTDFSPDVGYNGYTREAYFSVGLQGIVE
27+
KDIETVRSLIDRTIDEVVEKGFEDDRIEALLHKIEIQMKHQSTSFGLMLTSYIASCWNHDGDPVELLKLGNQLAK
28+
FRQCLQENPKFLQEKVKQYFKNNQHKLTLSMRPDDKYHEKQAQVEATKLKQKVEALSPGDRQQIYEKGLELRSQQ
29+
SKPQDASCLPALKVSDIEPTIPVTELDVVLTAGDIPVQYCAQPTNGMVYFRAFSSLNTLPEELRPYVPLFCSVLT
30+
KLGCGLLDYREQAQQIELKTGGMSASPHVLPDDSHMDTYEQGVLFSSLCLDRNLPDMMQLWSEIFNNPCFEEEEH
31+
FKVLVKMTAQELANGIPDSGHLYASIRAGRTLTPAGDLQETFSGMDQVRLMKRIAEMTDIKPILRKLPRIKKHLL
32+
NGDNMRCSVNATPQQMPQTEKAVEDFLRSIGRSKKERRPVRPHTVEKPVPSSSGGDAHVPHGSQVIRKLVMEPTF
33+
KPWQMKTHFLMPFPVNYVGECIRTVPYTDPDHASLKILARLMTAKFLHTEIREKGGAYGGGAKLSHNGIFTLYSY
34+
RDPNTIETLQSFGKAVDWAKSGKFTQQDIDEAKLSVFSTVDAPVAPSDKGMDHFLYGLSDEMKQAHREQLFAVSH
35+
DKLLAVSDRYLGTGKSTHGLAILGPENPKIAKDPSWIIR------------------------------------
36+
-----*

0 commit comments

Comments
 (0)