def estimate_bilayerDist_hack(self, dmin=5.0, dmax=30.0, step=0.5, max_imbalance=0.2): """ DEPRECATED """ for cutoff in np.arange(dmin, dmax, step): LF = LeafletFinder(self.universe, self.phosphates, cutoff=cutoff) sizes = LF.sizes() if len(sizes) < 2: continue size_values = sizes.values() max_val = max(size_values) max_index = size_values.index(max_val) size_values[max_index] = 0 second_max_val = max(size_values) second_max_index = size_values.index(second_max_val) imbalance = np.abs(max_val - second_max_val) / (max_val + second_max_val) print cutoff, len(sizes), imbalance if imbalance > max_imbalance: break else: sizes = (cutoff, len(LF.sizes())) self.bilayerDist = sizes
def determine_leaflets(universe, phosphateSelection="name P*"): ''' From a selection of phosphates, determine which belong to the upper and lower leaflets. Keyword arguments: universe -- an MDAnalysis Universe object phosphateSelection -- a string specifying how to select the phosphate atoms (e.g. "name P1") ''' leaflets = {} #print(universe) # calculate the z value of the phosphates defining the bilayer (assumes bilayer is in x and y..) #po4=universe.atoms.select_atoms(phosphateSelection) #bilayerCentre = po4.center_of_geometry()[2] #print(bilayerCentre) # apply the MDAnalysis LeafletFinder graph-based method to determine the two largest groups which # should correspond to the upper and lower leaflets phosphates = LeafletFinder(universe, phosphateSelection) # find the two largest groups - required as the first two returned by LeafletFinder, whilst usually are the largest, this is not always so (a, b) = largest_groups(phosphates.sizes()) layer1_avz = np.mean(phosphates.group(a).center_of_geometry()[2]) layer2_avz = np.mean(phosphates.group(b).center_of_geometry()[2]) bilayerCentre = (layer1_avz + layer2_avz) / 2. # check to see where the first leaflet lies if phosphates.group(a).centroid()[2] > bilayerCentre: #print(phosphates.group(b).residues.atoms) leaflets["upper"] = phosphates.group(a).residues.atoms leaflets["lower"] = phosphates.group(b).residues.atoms else: leaflets["lower"] = phosphates.group(a).residues.atoms leaflets["upper"] = phosphates.group(b).residues.atoms return leaflets
def determine_leaflets(universe,phosphateSelection): ''' From a selection of phosphates, determine which belong to the upper and lower leaflets. Keyword arguments: universe -- an MDAnalysis Universe object phosphateSelection -- a string specifying how to select the phosphate atoms (e.g. "name P1") ''' leaflets = {} # calculate the z value of the phosphates defining the bilayer (assumes bilayer is in x and y..) po4=universe.selectAtoms(phosphateSelection) bilayerCentre = po4.centerOfGeometry()[2] # apply the MDAnalysis LeafletFinder graph-based method to determine the two largest groups which # should correspond to the upper and lower leaflets phosphates = LeafletFinder(universe,phosphateSelection) # find the two largest groups - required as the first two returned by LeafletFinder, whilst usually are the largest, this is not always so (a,b) = largest_groups(phosphates.sizes()) # check to see where the first leaflet lies if phosphates.group(a).centroid()[2] > bilayerCentre: leaflets[1] = phosphates.group(a) leaflets[2] = phosphates.group(b) else: leaflets[2] = phosphates.group(a) leaflets[1] = phosphates.group(b) return leaflets
more sophisticated example. LeafletFinder Algorithm ----------------------- 1. build a graph of all phosphate distances < cutoff 2. identify the largest connected subgraphs 3. analyse first and second largest graph (assume they are the leaflets, anything else are stray micelles or individually floating lipids) One could identify group 1 and 2 as upper and lower leaflet by comparing the median of the centres of masses; this is left as an exercise... """ from MDAnalysis.analysis.leaflet import LeafletFinder if __name__ == "__main__": import sys try: PDB, selection = sys.argv[1:3] except ValueError: print "usage: leaflet.py PDB SELECTION" sys.exit(1) print "PDB=%(PDB)r selection=%(selection)r" % vars() L = LeafletFinder(PDB, selection) print "Number of lipids in leaflets: %r" % L.sizes() macrovmd = PDB + ".vmd" L.write_vmd(macrovmd) print "Load macros for vmd from file %r" % macrovmd
cutoff, N = optimize_cutoff(u, options.selection, pbc=options.pbc, max_imbalance=options.max_imbalance) except: raise RuntimeError( "Failed cutoff optimization, try without --optimize") print "# Optimized cutoff={cutoff:.1f} A, finding {N:d} disconnected groups".format( **vars()) else: cutoff = options.cutoff print "# Using fixed cutoff={cutoff:.1f} A".format(**vars()) LF = LeafletFinder(u, options.selection, cutoff=cutoff, pbc=options.pbc) print "# group sizes = {0!r} ".format(LF.sizes()) # two leaflets def print_line(symbol="-"): print "#" + (12 + 5) * symbol print_line("=") print "#{0!s:>2} {1!s:>5} {2!s:>6}".format("ll", "resn", "count") print_line("=") for groupindex in xrange(len(LF.components)): resnames = [a.resname for a in LF.groups(groupindex)] # there CERTAINLY is a better way to count occurrences than this... keys = np.unique(resnames) for k in keys: count = resnames.count(k)
if options.optimize: print "# Finding best cutoff (--optimize)..." try: cutoff, N = optimize_cutoff(u, options.selection, pbc=options.pbc, max_imbalance=options.max_imbalance) except: raise RuntimeError("Failed cutoff optimization, try without --optimize") print "# Optimized cutoff=%(cutoff).1f A, finding %(N)d disconnected groups" % vars() else: cutoff = options.cutoff print "# Using fixed cutoff=%(cutoff).1f A" % vars() LF = LeafletFinder(u, options.selection, cutoff=cutoff, pbc=options.pbc) print "# group sizes = %r " % LF.sizes() # two leaflets def print_line(symbol="-"): print "#" + (12 + 5) * symbol print_line("=") print "#%2s %5s %6s" % ("ll", "resn", "count") print_line("=") for groupindex in xrange(len(LF.components)): resnames = [a.resname for a in LF.groups(groupindex)] # there CERTAINLY is a better way to count occurrences than this... keys = np.unique(resnames) for k in keys: count = resnames.count(k)
class mem_analysis: """ Class for analysis of membranes from .data and .xtc files """ def __init__(self, prefix, pre_out=None): """ Reads .data and .xtc into universe Defines static atomgroups based on type Reads parameter values (nsteps, nlipids) Initiates bbox and leaflets based on first frame Initiates dictionary out for storage of data Writes lipid type to out['lip'] """ if not pre_out: self.pre_out = prefix else: self.pre_out = pre_out self.u = mda.Universe(prefix + '.data', prefix + '.xtc') self.ref = mda.Universe(prefix + '.data') self.nsteps = len(self.u.trajectory) self.ts = 0 b = self.u.trajectory[0].dimensions[0:3] self.bbox = np.array([0, 0, 0, b[0], b[1], b[2]]).reshape(2,3) # Define atomgroups self.atomgroups = {} self.atomgroups['nc3'] = self.u.select_atoms('type 1', updating=True) self.atomgroups['dopc'] = self.u.select_atoms('type 2', updating=True) self.atomgroups['dogl'] = self.u.select_atoms('type 9', updating=True) self.atomgroups['tails'] = self.u.select_atoms('type 7', updating=True) self.atomgroups['heads'] = self.u.select_atoms('type 2 9', updating=True) self.dnlipids = len(self.atomgroups['heads']) self.membranes = {} # Set leaflets self.leaflets = LeafletFinder(self.u, self.atomgroups['dopc'], cutoff=15, pbc=True) sizes = np.array(list(self.leaflets.sizes().values())) l = [self.leaflets.groups(i) for i in np.argsort(-sizes)[:2]] if l[0].center_of_geometry()[2] > l[1].center_of_geometry()[2]: self.atomgroups['ul_dopc'], self.atomgroups['ll_dopc'] = l[0], l[1] else: self.atomgroups['ul_dopc'], self.atomgroups['ll_dopc'] = l[1], l[0] # Make out dict self.out = {'lip':[],'r':[], 's': [], 'j': [], 'k': [], 'd': [], 'rho': [], 'l': [], 'apl': [], 'd_nc3':[]} self.out_box = [] for key in self.out.keys(): self.out[key] = [[] for i in range(len(self.atomgroups['heads']))] # Add lipid types to out['lip'] for head in self.atomgroups['heads']: if head in self.atomgroups['dopc']: self.out['lip'][head.resid - 1] = 'dopc' else: self.out['lip'][head.resid - 1] = 'dogl' def update_membranes(self): """ Computes all membranes Updates dynamic atomgroups """ self.membranes['ul_dopc'] = Membrane(self.atomgroups['ul_dopc'].atoms.positions, labels=self.atomgroups['ul_dopc'].atoms.resids, periodic=True, bbox=self.bbox, boundary_layer=0.5) self.membranes['ul_dopc'].fit_points_to_box_xy() self.membranes['ul_dopc'].compute_pnormals(knbrs=36) self.membranes['ul_dopc'].compute_approx_surface(exactness_level=8) self.membranes['ul_dopc'].compute_membrane_surface() self.membranes['ul_dopc'].compute_properties() self.membranes['ll_dopc'] = Membrane(self.atomgroups['ll_dopc'].atoms.positions, labels=self.atomgroups['ll_dopc'].atoms.resids, periodic=True, bbox=self.bbox, boundary_layer=0.5) self.membranes['ll_dopc'].fit_points_to_box_xy() self.membranes['ll_dopc'].compute_pnormals(knbrs=36) self.membranes['ll_dopc'].compute_approx_surface(exactness_level=8) self.membranes['ll_dopc'].compute_membrane_surface() self.membranes['ll_dopc'].compute_properties() Membrane.compute_thickness(self.membranes['ul_dopc'], self.membranes['ll_dopc']) # Generate NC3 membranes self.atomgroups['ul_nc3'] = self.u.select_atoms('resid ' + ' '.join(map(str, self.atomgroups['ul_dopc'].atoms.resids))).intersection(self.atomgroups['nc3']) self.atomgroups['ll_nc3'] = self.u.select_atoms('resid ' + ' '.join(map(str, self.atomgroups['ll_dopc'].atoms.resids))).intersection(self.atomgroups['nc3']) self.membranes['ul_nc3'] = Membrane(self.atomgroups['ul_nc3'].atoms.positions, labels=self.atomgroups['ul_nc3'].atoms.resids, periodic=True, bbox=self.bbox, boundary_layer=0.5) self.membranes['ul_nc3'].fit_points_to_box_xy() self.membranes['ul_nc3'].compute_pnormals(knbrs=36) self.membranes['ul_nc3'].compute_approx_surface(exactness_level=8) self.membranes['ul_nc3'].compute_membrane_surface() self.membranes['ul_nc3'].compute_properties() self.membranes['ll_nc3'] = Membrane(self.atomgroups['ll_nc3'].atoms.positions, labels=self.atomgroups['ll_nc3'].atoms.resids, periodic=True, bbox=self.bbox, boundary_layer=0.5) self.membranes['ll_nc3'].fit_points_to_box_xy() self.membranes['ll_nc3'].compute_pnormals(knbrs=36) self.membranes['ll_nc3'].compute_approx_surface(exactness_level=8) self.membranes['ll_nc3'].compute_membrane_surface() self.membranes['ll_nc3'].compute_properties() # Compute all distances from dogl to closest membrane and determine upper / lower / flipflop self.membranes['dogl'] = Membrane.compute(self.atomgroups['dogl'].atoms.positions, self.atomgroups['dogl'].atoms.resids, periodic=True, bbox=self.bbox) Membrane.compute_thickness(self.membranes['dogl'], self.membranes['ul_nc3'], mtype='exact') self.ul_dogl_dist = np.column_stack((self.membranes['dogl'].labels, self.membranes['dogl'].properties['thickness'])) ul_dogl_labels = np.array([int(lip[0]) for lip in self.ul_dogl_dist if lip[1] < flipflop_offset]) if len(ul_dogl_labels) > 0: self.atomgroups['ul_dogl'] = self.u.select_atoms('resid ' + ' '.join(map(str, ul_dogl_labels))).intersection(self.atomgroups['dogl']) else: self.atomgroups['ul_dogl'] = self.u.atoms[[]] Membrane.compute_thickness(self.membranes['dogl'], self.membranes['ll_nc3'], mtype='exact') self.ll_dogl_dist = np.column_stack((self.membranes['dogl'].labels, self.membranes['dogl'].properties['thickness'])) ll_dogl_labels = np.array([int(lip[0]) for lip in self.ll_dogl_dist if lip[1] < flipflop_offset]) if len(ll_dogl_labels) > 0: self.atomgroups['ll_dogl'] = self.u.select_atoms('resid ' + ' '.join(map(str, ll_dogl_labels))).intersection(self.atomgroups['dogl']) else: self.atomgroups['ll_dogl'] = self.u.atoms[[]] # Generate ff_dogl membrane from lipids not in ul and ll ff_dogl_labels = np.array([lip for lip in self.membranes['dogl'].labels if lip not in np.union1d(ul_dogl_labels, ll_dogl_labels)]) if len(ff_dogl_labels) > 0: self.atomgroups['ff_dogl'] = self.u.select_atoms('resid ' + ' '.join(map(str, ff_dogl_labels))).intersection(self.atomgroups['dogl']) else: self.atomgroups['ff_dogl'] = self.u.atoms[[]] # Generate combines membranes self.atomgroups['ul'] = self.atomgroups['ul_dopc'] + self.atomgroups['ul_dogl'] self.atomgroups['ll'] = self.atomgroups['ll_dopc'] + self.atomgroups['ll_dogl'] self.membranes['ul'] = Membrane(self.atomgroups['ul'].atoms.positions, labels=self.atomgroups['ul'].atoms.resids, periodic=True, bbox=self.bbox, boundary_layer=0.5) self.membranes['ul'].fit_points_to_box_xy() self.membranes['ul'].compute_pnormals(knbrs=36) self.membranes['ul'].compute_approx_surface(exactness_level=8) self.membranes['ul'].compute_membrane_surface() self.membranes['ul'].compute_properties() self.membranes['ll'] = Membrane(self.atomgroups['ll'].atoms.positions, labels=self.atomgroups['ll'].atoms.resids, periodic=True, bbox=self.bbox, boundary_layer=0.5) self.membranes['ll'].fit_points_to_box_xy() self.membranes['ll'].compute_pnormals(knbrs=36) self.membranes['ll'].compute_approx_surface(exactness_level=8) self.membranes['ll'].compute_membrane_surface() self.membranes['ll'].compute_properties() # Compute thickness and densities self.membranes['ul'].compute_density(rho_type, sigma, 'density', True, self.membranes['ul'].labels) self.membranes['ll'].compute_density(rho_type, sigma, 'density', True, self.membranes['ll'].labels) Membrane.compute_thickness(self.membranes['ul_nc3'], self.membranes['ll_nc3']) for key in self.membranes: self.membranes[key].write_all(self.pre_out + '/' + key + '_' + str(self.ts)) def write_to_out(self): """ Save all lipids to self.out. Switch case for lipid type and u/l/f """ for head in self.atomgroups['heads']: if head in self.atomgroups['ul_dopc']: i_ul_dopc = np.where(self.membranes['ul_dopc'].labels==head.resid)[0][0] i_ul_nc3 = np.where(self.membranes['ul_nc3'].labels==head.resid)[0][0] i_ul = np.where(self.membranes['ul'].labels==head.resid)[0][0] self.out['l'][head.resid - 1].append('u') self.out['r'][head.resid - 1].append(head.position) self.out['d'][head.resid - 1].append('na') self.out['d_nc3'][head.resid - 1].append(self.membranes['ul_nc3'].properties['thickness'][i_ul_nc3]) self.out['rho'][head.resid - 1].append(self.membranes['ul'].properties['density'][i_ul]) self.out['j'][head.resid - 1].append(self.membranes['ul'].memb_smooth.mean_curv[i_ul]) self.out['k'][head.resid - 1].append(self.membranes['ul'].memb_smooth.gaus_curv[i_ul]) self.out['apl'][head.resid - 1].append(self.membranes['ul'].memb_smooth.pareas[i_ul]) elif head in self.atomgroups['ll_dopc']: i_ll_dopc = np.where(self.membranes['ll_dopc'].labels==head.resid)[0][0] i_ll_nc3 = np.where(self.membranes['ll_nc3'].labels==head.resid)[0][0] i_ll = np.where(self.membranes['ll'].labels==head.resid)[0][0] self.out['l'][head.resid - 1].append('l') self.out['r'][head.resid - 1].append(head.position) self.out['d'][head.resid - 1].append('na') self.out['d_nc3'][head.resid - 1].append(self.membranes['ll_nc3'].properties['thickness'][i_ll_nc3]) self.out['rho'][head.resid - 1].append(self.membranes['ll'].properties['density'][i_ll]) self.out['j'][head.resid - 1].append(self.membranes['ll'].memb_smooth.mean_curv[i_ll]) self.out['k'][head.resid - 1].append(self.membranes['ll'].memb_smooth.gaus_curv[i_ll]) self.out['apl'][head.resid - 1].append(self.membranes['ll'].memb_smooth.pareas[i_ll]) elif head in self.atomgroups['ul_dogl']: i_ul = np.where(self.membranes['ul'].labels==head.resid)[0][0] self.out['l'][head.resid - 1].append('u') self.out['r'][head.resid - 1].append(head.position) d_ul = self.ul_dogl_dist[self.ul_dogl_dist[:,0]==head.resid, 1] d_ll = self.ll_dogl_dist[self.ll_dogl_dist[:,0]==head.resid, 1] self.out['d'][head.resid - 1].append([d_ul, d_ll]) self.out['d_nc3'][head.resid - 1].append('na') self.out['rho'][head.resid - 1].append(self.membranes['ul'].properties['density'][i_ul]) self.out['j'][head.resid - 1].append(self.membranes['ul'].memb_smooth.mean_curv[i_ul]) self.out['k'][head.resid - 1].append(self.membranes['ul'].memb_smooth.gaus_curv[i_ul]) self.out['apl'][head.resid - 1].append(self.membranes['ul'].memb_smooth.pareas[i_ul]) elif head in self.atomgroups['ll_dogl']: i_ll = np.where(self.membranes['ll'].labels==head.resid)[0][0] self.out['l'][head.resid - 1].append('l') self.out['r'][head.resid - 1].append(head.position) d_ul = self.ul_dogl_dist[self.ul_dogl_dist[:,0]==head.resid, 1] d_ll = self.ll_dogl_dist[self.ll_dogl_dist[:,0]==head.resid, 1] self.out['d'][head.resid - 1].append([d_ul, d_ll]) self.out['d_nc3'][head.resid - 1].append('na') self.out['rho'][head.resid - 1].append(self.membranes['ll'].properties['density'][i_ll]) self.out['j'][head.resid - 1].append(self.membranes['ll'].memb_smooth.mean_curv[i_ll]) self.out['k'][head.resid - 1].append(self.membranes['ll'].memb_smooth.gaus_curv[i_ll]) self.out['apl'][head.resid - 1].append(self.membranes['ll'].memb_smooth.pareas[i_ll]) elif head in self.atomgroups['ff_dogl']: self.out['l'][head.resid - 1].append('f') self.out['r'][head.resid - 1].append(head.position) d_ul = self.ul_dogl_dist[self.ul_dogl_dist[:,0]==head.resid, 1] d_ll = self.ll_dogl_dist[self.ll_dogl_dist[:,0]==head.resid, 1] self.out['d'][head.resid - 1].append([d_ul, d_ll]) self.out['d_nc3'][head.resid - 1].append('na') self.out['rho'][head.resid - 1].append('na') self.out['j'][head.resid - 1].append('na') self.out['k'][head.resid - 1].append('na') self.out['apl'][head.resid - 1].append('na') def write_to_json(self): with open(self.pre_out + '.json', 'w') as f: json.dump(self.out, f, cls=NumpyEncoder) def run(self, trange=None): """ Loops over trajectory Update ul_dopc and ll_dopc every n steps (dopc's generally don't flipflop) Call update_membranes to recalculate membranes Call write_out to add properties to self.out """ if not trange: trange = (0, self.nsteps) elif len(trange) == 1: trange = (trange[0], self.nsteps) print(trange) print(len(self.u.trajectory)) for ts in self.u.trajectory[trange[0] : trange[1] : 1]: print(ts.frame) self.ts = ts.frame b = ts.dimensions[0:3] self.bbox = np.array([0,0,0, b[0], b[1], b[2]]).reshape(2,3) self.out_box.append(self.bbox) self.update_membranes() self.write_to_out() self.write_to_json()
3. analyse first and second largest graph (assume they are the leaflets, anything else are stray micelles or individually floating lipids) One could identify group 1 and 2 as upper and lower leaflet by comparing the median of the centres of masses; this is left as an exercise... """ import numpy import MDAnalysis from MDAnalysis.analysis.leaflet import LeafletFinder if __name__ == "__main__": import sys try: PDB, selection = sys.argv[1:3] except ValueError: print "usage: leaflet.py PDB SELECTION" sys.exit(1) print "PDB=%(PDB)r selection=%(selection)r" % vars() L = LeafletFinder(PDB, selection) print "Number of lipids in leaflets: %r" % L.sizes() macrovmd = PDB + ".vmd" L.write_vmd(macrovmd) print "Load macros for vmd from file %r" % macrovmd
more sophisticated example. LeafletFinder Algorithm ----------------------- 1. build a graph of all phosphate distances < cutoff 2. identify the largest connected subgraphs 3. analyse first and second largest graph (assume they are the leaflets, anything else are stray micelles or individually floating lipids) One could identify group 1 and 2 as upper and lower leaflet by comparing the median of the centres of masses; this is left as an exercise... """ from MDAnalysis.analysis.leaflet import LeafletFinder if __name__ == "__main__": import sys try: PDB, selection = sys.argv[1:3] except ValueError: print "usage: leaflet.py PDB SELECTION" sys.exit(1) print "PDB={PDB!r} selection={selection!r}".format(**vars()) L = LeafletFinder(PDB, selection) print "Number of lipids in leaflets: {0!r}".format(L.sizes()) macrovmd = PDB + ".vmd" L.write_vmd(macrovmd) print "Load macros for vmd from file {0!r}".format(macrovmd)
if options.optimize: print "# Finding best cutoff (--optimize)..." try: cutoff, N = optimize_cutoff(u, options.selection, pbc=options.pbc, max_imbalance=options.max_imbalance) except: raise RuntimeError("Failed cutoff optimization, try without --optimize") print "# Optimized cutoff={cutoff:.1f} A, finding {N:d} disconnected groups".format(**vars()) else: cutoff = options.cutoff print "# Using fixed cutoff={cutoff:.1f} A".format(**vars()) LF = LeafletFinder(u, options.selection, cutoff=cutoff, pbc=options.pbc) print "# group sizes = {0!r} ".format(LF.sizes()) # two leaflets def print_line(symbol="-"): print "#" + (12 + 5) * symbol print_line("=") print "#{0!s:>2} {1!s:>5} {2!s:>6}".format("ll", "resn", "count") print_line("=") for groupindex in xrange(len(LF.components)): resnames = [a.resname for a in LF.groups(groupindex)] # there CERTAINLY is a better way to count occurrences than this... keys = np.unique(resnames) for k in keys: count = resnames.count(k)