| import os,sys
|
|
|
| from colabdesign.mpnn import mk_mpnn_model
|
| from colabdesign.af import mk_af_model
|
| from colabdesign.shared.protein import pdb_to_string
|
| from colabdesign.shared.parse_args import parse_args
|
|
|
| import pandas as pd
|
| import numpy as np
|
| from string import ascii_uppercase, ascii_lowercase
|
| alphabet_list = list(ascii_uppercase+ascii_lowercase)
|
|
|
| def get_info(contig):
|
| F = []
|
| free_chain = False
|
| fixed_chain = False
|
| sub_contigs = [x.split("-") for x in contig.split("/")]
|
| for n,(a,b) in enumerate(sub_contigs):
|
| if a[0].isalpha():
|
| L = int(b)-int(a[1:]) + 1
|
| F += [1] * L
|
| fixed_chain = True
|
| else:
|
| L = int(b)
|
| F += [0] * L
|
| free_chain = True
|
| return F,[fixed_chain,free_chain]
|
|
|
| def main(argv):
|
| ag = parse_args()
|
| ag.txt("-------------------------------------------------------------------------------------")
|
| ag.txt("Designability Test")
|
| ag.txt("-------------------------------------------------------------------------------------")
|
| ag.txt("REQUIRED")
|
| ag.txt("-------------------------------------------------------------------------------------")
|
| ag.add(["pdb=" ], None, str, ["input pdb"])
|
| ag.add(["loc=" ], None, str, ["location to save results"])
|
| ag.add(["contigs=" ], None, str, ["contig definition"])
|
| ag.txt("-------------------------------------------------------------------------------------")
|
| ag.txt("OPTIONAL")
|
| ag.txt("-------------------------------------------------------------------------------------")
|
| ag.add(["copies=" ], 1, int, ["number of repeating copies"])
|
| ag.add(["num_seqs=" ], 8, int, ["number of mpnn designs to evaluate"])
|
| ag.add(["initial_guess" ], False, None, ["initialize previous coordinates"])
|
| ag.add(["use_multimer" ], False, None, ["use alphafold_multimer_v3"])
|
| ag.add(["use_soluble" ], False, None, ["use solubleMPNN"])
|
| ag.add(["num_recycles=" ], 3, int, ["number of recycles"])
|
| ag.add(["rm_aa="], "C", str, ["disable specific amino acids from being sampled"])
|
| ag.add(["num_designs=" ], 1, int, ["number of designs to evaluate"])
|
| ag.add(["mpnn_sampling_temp=" ], 0.1, float, ["sampling temperature used by proteinMPNN"])
|
| ag.txt("-------------------------------------------------------------------------------------")
|
| o = ag.parse(argv)
|
|
|
| if None in [o.pdb, o.loc, o.contigs]:
|
| ag.usage("Missing Required Arguments")
|
|
|
| if o.rm_aa == "":
|
| o.rm_aa = None
|
|
|
|
|
| contigs = []
|
| for contig_str in o.contigs.replace(" ",":").replace(",",":").split(":"):
|
| if len(contig_str) > 0:
|
| contig = []
|
| for x in contig_str.split("/"):
|
| if x != "0": contig.append(x)
|
| contigs.append("/".join(contig))
|
|
|
| chains = alphabet_list[:len(contigs)]
|
| info = [get_info(x) for x in contigs]
|
| fixed_pos = []
|
| fixed_chains = []
|
| free_chains = []
|
| both_chains = []
|
| for pos,(fixed_chain,free_chain) in info:
|
| fixed_pos += pos
|
| fixed_chains += [fixed_chain and not free_chain]
|
| free_chains += [free_chain and not fixed_chain]
|
| both_chains += [fixed_chain and free_chain]
|
|
|
| flags = {"initial_guess":o.initial_guess,
|
| "best_metric":"rmsd",
|
| "use_multimer":o.use_multimer,
|
| "model_names":["model_1_multimer_v3" if o.use_multimer else "model_1_ptm"]}
|
|
|
| if sum(both_chains) == 0 and sum(fixed_chains) > 0 and sum(free_chains) > 0:
|
| protocol = "binder"
|
| print("protocol=binder")
|
| target_chains = []
|
| binder_chains = []
|
| for n,x in enumerate(fixed_chains):
|
| if x: target_chains.append(chains[n])
|
| else: binder_chains.append(chains[n])
|
| af_model = mk_af_model(protocol="binder",**flags)
|
| prep_flags = {"target_chain":",".join(target_chains),
|
| "binder_chain":",".join(binder_chains),
|
| "rm_aa":o.rm_aa}
|
| opt_extra = {}
|
|
|
| elif sum(fixed_pos) > 0:
|
| protocol = "partial"
|
| print("protocol=partial")
|
| af_model = mk_af_model(protocol="fixbb",
|
| use_templates=True,
|
| **flags)
|
| rm_template = np.array(fixed_pos) == 0
|
| prep_flags = {"chain":",".join(chains),
|
| "rm_template":rm_template,
|
| "rm_template_seq":rm_template,
|
| "copies":o.copies,
|
| "homooligomer":o.copies>1,
|
| "rm_aa":o.rm_aa}
|
| else:
|
| protocol = "fixbb"
|
| print("protocol=fixbb")
|
| af_model = mk_af_model(protocol="fixbb",**flags)
|
| prep_flags = {"chain":",".join(chains),
|
| "copies":o.copies,
|
| "homooligomer":o.copies>1,
|
| "rm_aa":o.rm_aa}
|
|
|
| batch_size = 8
|
| if o.num_seqs < batch_size:
|
| batch_size = o.num_seqs
|
|
|
| print("running proteinMPNN...")
|
| sampling_temp = o.mpnn_sampling_temp
|
| mpnn_model = mk_mpnn_model(weights="soluble" if o.use_soluble else "original")
|
| outs = []
|
| pdbs = []
|
| for m in range(o.num_designs):
|
| if o.num_designs == 0:
|
| pdb_filename = o.pdb
|
| else:
|
| pdb_filename = o.pdb.replace("_0.pdb",f"_{m}.pdb")
|
| pdbs.append(pdb_filename)
|
| af_model.prep_inputs(pdb_filename, **prep_flags)
|
| if protocol == "partial":
|
| p = np.where(fixed_pos)[0]
|
| af_model.opt["fix_pos"] = p[p < af_model._len]
|
|
|
| mpnn_model.get_af_inputs(af_model)
|
| outs.append(mpnn_model.sample(num=o.num_seqs//batch_size, batch=batch_size, temperature=sampling_temp))
|
|
|
| if protocol == "binder":
|
| af_terms = ["plddt","i_ptm","i_pae","rmsd"]
|
| elif o.copies > 1:
|
| af_terms = ["plddt","ptm","i_ptm","pae","i_pae","rmsd"]
|
| else:
|
| af_terms = ["plddt","ptm","pae","rmsd"]
|
|
|
| labels = ["design","n","score"] + af_terms + ["seq"]
|
| data = []
|
| best = {"rmsd":np.inf,"design":0,"n":0}
|
| print("running AlphaFold...")
|
| os.system(f"mkdir -p {o.loc}/all_pdb")
|
| with open(f"{o.loc}/design.fasta","w") as fasta:
|
| for m,(out,pdb_filename) in enumerate(zip(outs,pdbs)):
|
| out["design"] = []
|
| out["n"] = []
|
| af_model.prep_inputs(pdb_filename, **prep_flags)
|
| for k in af_terms: out[k] = []
|
| for n in range(o.num_seqs):
|
| out["design"].append(m)
|
| out["n"].append(n)
|
| sub_seq = out["seq"][n].replace("/","")[-af_model._len:]
|
| af_model.predict(seq=sub_seq, num_recycles=o.num_recycles, verbose=False)
|
| for t in af_terms: out[t].append(af_model.aux["log"][t])
|
| if "i_pae" in out:
|
| out["i_pae"][-1] = out["i_pae"][-1] * 31
|
| if "pae" in out:
|
| out["pae"][-1] = out["pae"][-1] * 31
|
| rmsd = out["rmsd"][-1]
|
| if rmsd < best["rmsd"]:
|
| best = {"design":m,"n":n,"rmsd":rmsd}
|
| af_model.save_current_pdb(f"{o.loc}/all_pdb/design{m}_n{n}.pdb")
|
| af_model._save_results(save_best=True, verbose=False)
|
| af_model._k += 1
|
| score_line = [f'design:{m} n:{n}',f'mpnn:{out["score"][n]:.3f}']
|
| for t in af_terms:
|
| score_line.append(f'{t}:{out[t][n]:.3f}')
|
| print(" ".join(score_line)+" "+out["seq"][n])
|
| line = f'>{"|".join(score_line)}\n{out["seq"][n]}'
|
| fasta.write(line+"\n")
|
| data += [[out[k][n] for k in labels] for n in range(o.num_seqs)]
|
| af_model.save_pdb(f"{o.loc}/best_design{m}.pdb")
|
|
|
|
|
| with open(f"{o.loc}/best.pdb", "w") as handle:
|
| remark_text = f"design {best['design']} N {best['n']} RMSD {best['rmsd']:.3f}"
|
| handle.write(f"REMARK 001 {remark_text}\n")
|
| handle.write(open(f"{o.loc}/best_design{best['design']}.pdb", "r").read())
|
|
|
| labels[2] = "mpnn"
|
| df = pd.DataFrame(data, columns=labels)
|
| df.to_csv(f'{o.loc}/mpnn_results.csv')
|
|
|
| if __name__ == "__main__":
|
| main(sys.argv[1:])
|
|
|