def centre_protein_gh(dict_of_systs, wrap=False, cent="geometry"): # The GroupHug class was created by Richard Gowers (https://github.com/richardjgowers) # in response to this question on the MDAnalysis forum: # https://groups.google.com/forum/#!topic/mdnalysis-discussion/umDpvbCmQiE class GroupHug: def __init__(self, center, *others): self.c = center self.o = others @staticmethod def calc_restoring_vec(ag1, ag2): box = ag1.dimensions[:3] dist = ag1.center_of_mass() - ag2.center_of_mass() return box * np.rint(dist / box) def __call__(self, ts): # loop over other atomgroups and shunt them into nearest image to center for i in self.o: rvec = self.calc_restoring_vec(self.c, i) i.translate(+rvec) return ts # Centre the protein in the box using MDAnalysis for ligand_name, syst in dict_of_systs.items(): u = dict_of_systs[ligand_name] ligand_resname = ligand_name[:3] print(ligand_resname) if ligand_resname == "lar": print("WARNING: This script should only be used for the NTRK3 6KZD system!") # hard code the protein chains for now -> only for 6KZD model chainA = u.select_atoms("resid 527-627") chainB = u.select_atoms("resid 648-713") chainC = u.select_atoms("resid 728-838") lig = u.select_atoms("resname " + ligand_resname) ions = u.select_atoms("resname NA CL") protein = u.select_atoms("protein or resname ACE NME") reference = u.copy().select_atoms("protein or resname ACE NME") not_protein = u.select_atoms("not protein and not resname ACE NME") protein_and_lig = u.select_atoms("protein or resname ACE NME " + ligand_resname) transforms = [ trans.unwrap(protein), trans.unwrap(lig), GroupHug(chainA, chainB, chainC, lig), trans.center_in_box(protein_and_lig, wrap=wrap, center="geometry"), trans.wrap(ions), trans.fit_rot_trans(protein, reference), ] dict_of_systs[ligand_name].trajectory.add_transformations(*transforms) return dict_of_systs
def centre_protein(dict_of_systs, wrap=False, cent="geometry"): # Centre the protein in the box using MDAnalysis for syst in dict_of_systs: u = dict_of_systs[syst] reference = u.copy().select_atoms("protein or resname ACE NME") protein = u.select_atoms("protein or resname ACE NME") not_protein = u.select_atoms("not protein") transforms = [ trans.center_in_box(protein, wrap=wrap, center=cent), trans.wrap(not_protein), trans.fit_rot_trans(protein, reference), ] dict_of_systs[syst].trajectory.add_transformations(*transforms) return dict_of_systs
fit_trans_cog = [] fit_trans_rmsd = [] for ts in u.trajectory: print("fit_trans frame:", ts.frame) fit_trans_cog.append(ag.centroid()) fit_trans_rmsd.append(rmsd(ag.positions, ref_pos)) u.trajectory[0] #---- # same thing with fit_rot_trans u = mda.Universe(dataset.topology, dataset.trajectory) ag = u.select_atoms("protein") ref = u.select_atoms("protein") ref_pos = ref.positions.copy() transform = fit_rot_trans(ag, ref, plane=None, weights=None) u.trajectory.add_transformations(transform) fit_trans_rot_cog = [] fit_trans_rot_rmsd = [] for ts in u.trajectory: fit_trans_rot_cog.append(ag.centroid()) fit_trans_rot_rmsd.append(rmsd(ag.positions, ref_pos)) #---- # remove translation in xy relative to self # in "static" second universe u = mda.Universe(dataset.topology, dataset.trajectory) ag = u.select_atoms("protein") ref_static = mda.Universe(dataset.topology, dataset.trajectory).select_atoms("protein") ref_pos = ref_static.positions.copy()
#get average structure numframes = len(u.trajectory) p_avg = np.zeros_like(base.positions) for ts in u.trajectory: p_avg += base.positions p_avg /= numframes base.positions = p_avg with md.Writer("TATA_avg.pdb",base.n_atoms) as W: W.write(base) u.trajectory.rewind() #align by removing rotation and translation ref = md.Universe("TATA_avg.pdb") transform = transformations.fit_rot_trans(base, ref, weights="mass") u.trajectory.add_transformations(transform) #write trajectories #discard first 5 ns (each frame = 10 ps) eqbm_time = 500 t = np.arange(eqbm_time,4500,100) for time in t: with md.Writer("TATA_traj_%d_ps.dcd"%(int(time*10)),base.n_atoms) as W: for ts in u.trajectory: if ts.frame > eqbm_time and ts.frame < eqbm_time + time: W.write(base)
print("Running production simulation ...") simulation.step(production_steps) if production_steps / production_trajectory_frequency >= 1: print("Transforming trajectory ...") u = mda.Universe( str(output_directory / "equilibration/out_state.pdb"), str(output_directory / "trajectory.xtc"), ) backbone = u.select_atoms("backbone") not_protein = u.select_atoms("not protein") workflow = ( transformations.unwrap(backbone), transformations.center_in_box(backbone), transformations.wrap(not_protein, compound="fragments"), transformations.fit_rot_trans(backbone, backbone), ) u.trajectory.add_transformations(*workflow) print("Saving transformed topology and trajectory ...") u.atoms.write(str(output_directory / "topology_wrapped.pdb")) with mda.Writer( str(output_directory / "trajectory_wrapped.xtc"), u.atoms.n_atoms ) as W: for ts in u.trajectory: W.write(u.atoms) print("Finished")
def populate_dict(chunk, dictionary, pdb_file, mutant_sel, project_code, frames_to_stride): interface_selection_strings = { "rbd": "segid A and (backbone and (resid 403 or resid 417 or resid 439 or resid 445-447 or resid 449 or resid 453 or resid 455 or resid 456 or resid 473-477 or resid 484-487 or resid 489 or resid 490 or resid 493-503 or resid 505 or resid 506))", "ace2": "segid C and (backbone and (resid 18 or resid 21 or resid 23-32 or resid 33-39 or resid 41 or resid 42 or resid 45 or resid 75 or resid 76 or resid 78-84))", "rbd_and_ace2": "(segid A and (backbone and (resid 403 or resid 417 or resid 439 or resid 445-447 or resid 449 or resid 453 or resid 455 or resid 456 or resid 473-477 or resid 484-487 or resid 489 or resid 490 or resid 493-503 or resid 505 or resid 506))) or (segid C and (backbone and (resid 18 or resid 21 or resid 23-32 or resid 33-39 or resid 41 or resid 42 or resid 45 or resid 75 or resid 76 or resid 78-84)))", } # Create a dictionary containing selection strings for MDAnalysis # residues 417 and 439 are not named since these are mutated across systems # segid C = ACE2, segid A = RBD # TODO remove project keys, not sure they are needed proj_mutant_dict = { "17311": { "WT": { "D30": "segid C and (resid 30 and name OD1 OD2)", "res417": "segid A and (resid 417 and name NZ)", "E329": "segid C and (resid 329 and name OE1 OE2)", "res439": "segid A and (resid 439 and name ND2)", "K31": "segid C and (resid 31 and name NZ)", "E484": "segid A and (resid 484 and name OE1 OE2)", "E35": "segid C and (resid 35 and name OE1 OE2)", "K31": "segid C and (resid 31 and name NZ)", "Q493": "segid A and (resid 493 and name NE2 OE1)", "K353": "segid C and (resid 353 and name NZ)", "G496bb": "segid A and (resid 496 and name O C CA N)", "D38": "segid C and (resid 38 and name OD1 OD2)", "Y449": "segid A and (resid 449 and name CG CD1 CE1 CZ CE2 CD2 OH)", "Q42": "segid C and (resid 42 and name NE2 OE1)", "K353bb": "segid C and (resid 353 and name O C CA N)", "G502bb": "segid A and (resid 502 and name O C CA N)", }, }, } # set the reference to be the equilibrated structure ref = mda.Universe(pdb_file) ref.trajectory[0] # there is only one frame anyway, but just to be sure ref_bb = ref.select_atoms("backbone") # the ref for RMSD calcs later # set reference interfaces ref_rbd_interface_bb = ref.select_atoms(interface_selection_strings["rbd"]) ref_ace2_interface_bb = ref.select_atoms( interface_selection_strings["ace2"]) ref_whole_interface_bb = ref.select_atoms( interface_selection_strings["rbd_and_ace2"]) reference = ref.select_atoms( "not resname Na+ Cl- HOH") # the ref for transforms later for traj in chunk: print("--> Analysing trajectory: ", traj) mobile = mda.Universe(pdb_file, traj) # centre the two protein chains in the box # this stops chains jumping across PBC chainA = mobile.select_atoms("segid A or segid B") # RBD + glycans chainB = mobile.select_atoms("segid C or segid D") # ACE2 + glycans ions = mobile.select_atoms("resname Na+ Cl- HOH") protein = mobile.select_atoms("not resname Na+ Cl- HOH") transforms = [ trans.unwrap(protein), GroupHug(chainA, chainB), trans.center_in_box(protein, wrap=False, center="geometry"), trans.wrap(ions), trans.fit_rot_trans(protein, reference), ] print("--> Centring protein chains in the box") mobile.trajectory.add_transformations(*transforms) # loop over each frame in the current trajectory, with a defined stride for ts in mobile.trajectory[::frames_to_stride]: print(f"--> Current frame: {ts.frame}") # calculate the key interactions # RBD --- ACE2 # D30 --- K417 D30 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["D30"]) res417 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["res417"]) D30_res417_dist_mindist = np.min( distances.distance_array(D30.positions, res417.positions)) # E329 --- N439 E329 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["E329"]) res439 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["res439"]) E329_res439_dist_mindist = np.min( distances.distance_array(E329.positions, res439.positions)) # E484 --- K31 K31 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["K31"]) E484 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["E484"]) E484_K31_dist_mindist = np.min( distances.distance_array(E484.positions, K31.positions)) # E35 --- K31 E35 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["E35"]) E35_K31_dist_mindist = np.min( distances.distance_array(E35.positions, K31.positions)) # E35 --- Q493 Q493 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["Q493"]) E35_Q493_dist_mindist = np.min( distances.distance_array(E35.positions, Q493.positions)) # Additional interactions K31_Q493_dist_mindist = np.min( distances.distance_array(K31.positions, Q493.positions)) # K353 --- G496 (K353 to G496 backbone) K353 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["K353"]) G496bb = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["G496bb"]) K353_G496bb_dist_mindist = np.min( distances.distance_array(K353.positions, G496bb.positions)) # D38 --- Y449 D38 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["D38"]) Y449 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["Y449"]) D38_Y449_dist_mindist = np.min( distances.distance_array(D38.positions, Y449.positions)) # Q42 --- Y449 Q42 = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["Q42"]) Q42_Y449_dist_mindist = np.min( distances.distance_array(Q42.positions, Y449.positions)) # K353bb --- G502bb (Backbone to backbone) K353bb = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["K353bb"]) G502bb = mobile.select_atoms( proj_mutant_dict[project_code][mutant]["G502bb"]) K353bb_G502bb_dist_mindist = np.min( distances.distance_array(K353bb.positions, G502bb.positions)) # sort out names for the dict traj_split = traj.split("/") key_name = f"{traj_split[6]}/{traj_split[7]}/{traj_split[8]}_{ts.frame}" # populate the dict - with placeholder keys for now dictionary[key_name] = { "d30_res417_mindist": D30_res417_dist_mindist, "e329_res439_mindist": E329_res439_dist_mindist, "e484_k31_mindist": E484_K31_dist_mindist, "e35_k31_mindist": E35_K31_dist_mindist, "e35_q493_mindist": E35_Q493_dist_mindist, "q493_k31_mindist": K31_Q493_dist_mindist, "k353_g496bb_mindist": K353_G496bb_dist_mindist, "d38_y449_dist_mindist": D38_Y449_dist_mindist, "q42_y449_dist_mindist": Q42_Y449_dist_mindist, "k353bb_g502bb_dist_mindist": K353bb_G502bb_dist_mindist, }