def calc_nematic_order(traj_filename, top_filename, output_filename, ndx_filename, n_chains): """Calculate the nematic order of both monolayers in a two monolayer system Returns the nematic order of each monolayer at each frame of a trajectory in a dual monolayer system. Parameters ---------- traj_filename : str Name of trajectory file top_filename : str Name of topology file output_filename : str Name of output file ndx_filename : str Name of Gromacs .ndx file which specifies atom groups n_chains : int Number of chains per monolayer """ groups = read_ndx(ndx_filename) bottom_chains = [id - 1 for id in groups['bottom_chains']] bottom_chains = [ chain.tolist() for chain in np.array_split(bottom_chains, n_chains) ] top_chains = [id - 1 for id in groups['top_chains']] top_chains = [ chain.tolist() for chain in np.array_split(top_chains, n_chains) ] traj = md.load(traj_filename, top=top_filename) S2_bottom = md.compute_nematic_order(traj, indices=bottom_chains) S2_top = md.compute_nematic_order(traj, indices=top_chains) np.savetxt(output_filename, np.column_stack((traj.time, S2_bottom, S2_top)), header='Time\tBottom\tTop')
def calc_nematic_order(traj_filename, top_filename, ndx_filename, output_filename, n_chains, C_only=False): """Calculate the nematic order of a monolayer Outputs the average nematic order at each frame of a trajectory between the top and bottom monolayers in a dual monolayer system. Output is directed to a file with the filename specified by the user. Parameters ---------- traj_filename : str Name of trajectory file (typically XTC format) top_filename : str Name of topology file (typically GRO format) ndx_filename : str Name of the GROMACS index file to read group information from output_filename : str Name of file to output results to n_chains : int Number of monolayer chains per surface C_only : bool, optional, default=False Only include carbon atoms in the calculation Notes ----- Only valid for single-component monolayers (assumes that all chains in a monolayer contain the same number of atoms). Only valid for systems featuring the same number of chains in each monolayer. To-do ----- Support for multi-component monolayers Support for systems where each monolayer features an arbitrary number of chains """ bottom_chains, top_chains = _gather_chains(top_filename, ndx_filename, n_chains, C_only=C_only) traj = md.load(traj_filename, top=top_filename) S2_bottom = md.compute_nematic_order(traj, indices=bottom_chains) S2_top = md.compute_nematic_order(traj, indices=top_chains) np.savetxt(output_filename, np.column_stack((traj.time, S2_bottom, S2_top)), header='Time\tBottom\tTop')
def test_order_from_traj(): """Made a perfectly aligned monolayer, should have S2 = 1 """ traj = md.load(get_fn('alkane-monolayer.pdb')) indices = [list(range(1900+x, 1900+x+36)) for x in range(0, 64*36, 36)] s2 = md.compute_nematic_order(traj, indices=indices) assert_allclose(1.0, s2)
def test_order_from_traj(get_fn): """Made a perfectly aligned monolayer, should have S2 = 1 """ traj = md.load(get_fn('alkane-monolayer.pdb')) indices = [ list(range(1900 + x, 1900 + x + 36)) for x in range(0, 64 * 36, 36) ] s2 = md.compute_nematic_order(traj, indices=indices) np.testing.assert_allclose(1.0, s2)
def calc_nematic_order(traj, lipid_dict): """Compute nematic order parameter Parameters ---------- traj : mdTraj traj() lipid_dict : dict() dictionary apping residue indices to associated atom indices Returns ------- s2_ave : float Average S2 over all frames s2_std : S2 standard dviation s2_list : Frame by frame list of S2 values Notes ----- Assumes 64 residues per leaflet """ top_chains = [] bot_chains = [] for i, key in enumerate(lipid_dict.keys()): indices = [int(item) for item in lipid_dict[key]] if i <= 63: top_chains.append(indices) else: bot_chains.append(indices) s2_top = mdtraj.compute_nematic_order(traj, indices=top_chains) s2_bot = mdtraj.compute_nematic_order(traj, indices=bot_chains) s2_list = (s2_top + s2_bot) / 2 #s2_blocks = s2_list[:-1].reshape(int((traj.n_frames-1)/250),250) #s2_block_avgs = np.mean(s2_blocks, axis = 1) s2_block_avgs = np.mean(s2_list) s2_ave = np.mean(s2_block_avgs) #s2_std = np.std(s2_block_avgs) s2_std = np.std(s2_list) return s2_ave, s2_std, s2_list
def calc_moving_s2(traj, tail_groups, selected_keys, window_size=3): """ Compute S2 over a moving window so you can look at different segments Parameters ---------- traj : MDTraj trajectory tail_groups : dict Keys: residue IDs Values: atom indices selected_keys: list residue IDs so we can pick out specific residue chains window_size: int, default 3 number of consecutive carbons to look at for S2 Returns ------- all_s2: array, traj.n_frames x n_carbons - window_size Each row is the nematic order for a frame Each column is the nematic order for that selection of chains. i.e. column 0 looks at the S2 for carbon[0,window_size) """ n_carbons = len([ a for a in tail_groups[selected_keys[0]] if 'H' != traj.topology.atom(a).name[0] ]) all_s2 = np.zeros((traj.n_frames, n_carbons - 3)) for i, carbon_start in enumerate(range(n_carbons - 3)): tail_no_h = { key: [ int(a) for a in tail_groups[key] if 'H' != traj.topology.atom(a).name[0] ] for key in tail_groups.keys() } sub_tails = [ tail_no_h[key][carbon_start:carbon_start + 3] for key in selected_keys ] all_s2[:, i] = mdtraj.compute_nematic_order(traj, indices=sub_tails) return all_s2
def calc_nematic_order(traj_filename, top_filename, output_filename, ndx_filename, chainlength): """Calculate the nematic order of a monolayer Returns the average nematic order at each frame of a trajectory between the top and bottom monolayers in a dual monolayer system. Parameters ---------- traj_filename : str Name of trajectory file top_filename : str Name of topology file output_filename : str Name of output file ndx_filename : str Name of Gromacs .ndx file which specifies atom groups chainlength : int Number of carbons per chain """ topology = md.load(top_filename).topology atoms = np.array(list(topology.atoms)) atom_names = [atom.name for atom in atoms] groups = read_ndx(ndx_filename) bottom_chains = [ id - 1 for id in groups['bottom_chains'] if atom_names[id - 1] == 'C' ] n_chains = int(len(bottom_chains) / chainlength) bottom_chains = [ chain.tolist() for chain in np.array_split(bottom_chains, n_chains) ] top_chains = [ id - 1 for id in groups['top_chains'] if atom_names[id - 1] == 'C' ] top_chains = [ chain.tolist() for chain in np.array_split(top_chains, n_chains) ] bottom_chemisorbed = [ id - 1 for id in groups['bottom_chemisorbed'] if atom_names[id - 1] == 'C' ] n_chemisorbed = int(len(bottom_chemisorbed) / chainlength) bottom_chemisorbed = [ chain.tolist() for chain in np.array_split(bottom_chemisorbed, n_chemisorbed) ] top_chemisorbed = [ id - 1 for id in groups['top_chemisorbed'] if atom_names[id - 1] == 'C' ] top_chemisorbed = [ chain.tolist() for chain in np.array_split(top_chemisorbed, n_chemisorbed) ] n_crosslinked = n_chains - n_chemisorbed if n_crosslinked > 0: bottom_crosslinked = [ id - 1 for id in groups['bottom_crosslinked'] if atom_names[id - 1] == 'C' ] bottom_crosslinked = [ chain.tolist() for chain in np.array_split(bottom_crosslinked, n_crosslinked) ] top_crosslinked = [ id - 1 for id in groups['top_crosslinked'] if atom_names[id - 1] == 'C' ] top_crosslinked = [ chain.tolist() for chain in np.array_split(top_crosslinked, n_crosslinked) ] traj = md.load(traj_filename, top=top_filename) S2_bottom = md.compute_nematic_order(traj, indices=bottom_chains) S2_top = md.compute_nematic_order(traj, indices=top_chains) S2_bottom_chemisorbed = md.compute_nematic_order( traj, indices=bottom_chemisorbed) S2_top_chemisorbed = md.compute_nematic_order(traj, indices=top_chemisorbed) if n_crosslinked > 0: S2_bottom_crosslinked = md.compute_nematic_order( traj, indices=bottom_crosslinked) S2_top_crosslinked = md.compute_nematic_order(traj, indices=top_crosslinked) S2_mean_crosslinked = np.mean( [S2_bottom_crosslinked, S2_top_crosslinked], axis=0) S2_mean_chains = np.mean([S2_bottom, S2_top], axis=0) S2_mean_chemisorbed = np.mean([S2_bottom_chemisorbed, S2_top_chemisorbed], axis=0) if n_crosslinked > 0: np.savetxt(output_filename, np.column_stack( (traj.time, S2_bottom, S2_top, S2_mean_chains, S2_bottom_chemisorbed, S2_top_chemisorbed, S2_mean_chemisorbed, S2_bottom_crosslinked, S2_top_crosslinked, S2_mean_crosslinked)), header='Time\tBottom\tTop\tAll-mean\t' + 'Bottom-chemisorbed\tTop-chemisorbed\tChemisorbed-mean\t' + 'Bottom-crosslinked\tTop-crosslinked\tCrosslinked-mean') else: np.savetxt(output_filename, np.column_stack((traj.time, S2_bottom, S2_top, S2_mean_chains, S2_bottom_chemisorbed, S2_top_chemisorbed, S2_mean_chemisorbed)), header='Time\tBottom\tTop\tAll-mean\t' + 'Bottom-chemisorbed\tTop-chemisorbed\tChemisorbed-mean')
toss = 1000 / dt # 1 ns traj = traj[toss:] # Nematic order parameter atoms_per_chain = (traj.n_atoms // 2 - 1800 - hydrogens_per_surface) // n_chains_per_surface bot_chain_indices = [[ n + x for x in range(atoms_per_chain) ] for n in range(1800, traj.n_atoms // 2 - hydrogens_per_surface, atoms_per_chain)] top_chain_indices = [[ n + x for x in range(atoms_per_chain) ] for n in range(traj.n_atoms // 2 + 1800, traj.n_atoms - hydrogens_per_surface, atoms_per_chain)] bot_s2 = md.compute_nematic_order(traj, indices=bot_chain_indices) top_s2 = md.compute_nematic_order(traj, indices=top_chain_indices) plt.plot(traj.time / 1000, bot_s2, alpha=0.5, lw=0.5, label='bot') plt.plot(traj.time / 1000, top_s2, alpha=0.5, lw=0.5, label='top') plt.ylim(0, 1) plt.xlabel('time (ns)') plt.ylabel('S2') plt.legend() plt.savefig('{}.png'.format(name), bbox_inches='tight') plt.clf() S2[name]['top'] = np.mean(top_s2) S2[name]['top_std'] = np.std(top_s2) S2[name]['bot'] = np.mean(bot_s2)