Exemple #1
0
def counterions(structure,top,includes=None,ff_includes=None,gro='counterions'):

	"""
	counterions(structure,top)
	Standard procedure for adding counterions.
	The resname must be understandable by "r RESNAME" in make_ndx and writes to the top file.
	"""

	#---we store the water resname in the wordspace as "sol"
	resname =  wordspace.get('sol','SOL')
	#---clean up the composition in case this is a restart
	for key in ['cation','anion',resname]:
		try: wordspace['composition'].pop(zip(*wordspace['composition'])[0].index(wordspace[key]))
		except: pass
	component(resname,count=wordspace['water_without_ions'])
	#---write the topology file as of the solvate step instead of copying them (genion overwrites top)
	write_top('counterions.top')
	gmx('grompp',base='genion',structure=structure,
		top='counterions',mdp='input-em-steep-in',
		log='grompp-genion')
	gmx('make_ndx',structure=structure,ndx='solvate-waters',
		inpipe='keep 0\nr %s\nkeep 1\nq\n'%resname,
		log='make-ndx-counterions-check')
	gmx('genion',base='genion',gro=gro,ndx='solvate-waters',
		cation=wordspace['cation'],anion=wordspace['anion'],
		flag='-conc %f -neutral'%wordspace['ionic_strength'],
		log='genion')
	with open(wordspace['step']+'log-genion','r') as fp: lines = fp.readlines()
	declare_ions = filter(lambda x:re.search('Will try',x)!=None,lines).pop()
	ion_counts = re.findall(
		'^Will try to add ([0-9]+)\+?\-? ([\w\+\-]+) ions and ([0-9]+) ([\w\+\-]+) ions',
		declare_ions).pop()
	for ii in range(2): component(ion_counts[2*ii+1],count=ion_counts[2*ii])
	component(resname,count=component(resname)-component(ion_counts[1])-component(ion_counts[3]))
	if includes:
		if type(includes)==str: includes = [includes]
		for i in includes: include(i)
	if ff_includes:
		if type(ff_includes)==str: ff_includes = [ff_includes]
		for i in ff_includes: include(i,ff=True)
	write_top('counterions.top')
Exemple #2
0
def makeshape():

	"""
	Generate the midplane points for various bilayer shapes.
	"""
	
	shape = wordspace['shape']
	lz = wordspace['solvent_thickness']
	binsize = wordspace['binsize']
	#---are the monolayers symmetric?
	monolayer_other = wordspace.get('monolayer_other',None)
	composition_other = wordspace.get('composition_other',None)
	if not monolayer_other and composition_other or not composition_other and monolayer_other:
		raise Exception('you must specify both "monolayer other" and "composition other"')
	monolayers = [[wordspace['monolayer_top'],wordspace['composition_top']]]
	if monolayer_other: monolayers += [[monolayer_other,composition_other]]
	else: monolayers += [monolayers[0]]
	#---compute spots on the 2D grid where we will place the lipids
	#---! note that we are still in 2D so the grid-spacing is only accurate for the flat bilayer
	spots,vecs = zip(*[random_lipids(total,composition,binsize) for total,composition in monolayers])
	#---for asymmetric bilayers we choose the larger set of box vectors
	vecs = transpose([max(i) for i in transpose(vecs)])
	pts = [np.concatenate(([s[:,0]],[s[:,1]],[np.zeros(len(s))])).T for s in spots]
	#---! non-flat points will be stretched in Z hence not evenly spaced in 3-space
	#---! needs 2 monolayers
	if shape == 'saddle':

		def bump(x,y,x0,y0,height,width):
			"""
			General function for producing a 2D Gaussian "dimple" or "bump".
			"""
			zs = height*np.exp(-(x-x0)**2/2/width**2)*\
				np.exp(-(y-y0)**2/2/width**2)
			return zs

		offsets = vecs[:2]/2.-2.
		bumpspots = [(0,1,1),(0,-1,1),(1,0,-1),(-1,0,-1)]
		for spot in bumpspots:
			pts[:,2] += bump(xys[:,0],xys[:,1],
				x0+offsets[0]*spot[0],y0+offsets[1]*spot[1],
				height*spot[2],width)
		ptsmid = np.concatenate(np.reshape(pts,(3*m,3*n,3))[m:2*m,n:2*n])
		ptsmid[:,0]-=vecs[0]
		ptsmid[:,1]-=vecs[1]
	
		if 0: meshplot(ptsmid,show='surf')
	
	#---! needs 2 monolayers
	elif shape == 'buckle':

		def buckle(x,y,height):
			zs = height*np.sin(x*2*pi/lx)
			return zs
		
		pts[:,2] += buckle(xys[:,0],xys[:,1],height)

	elif shape == 'flat': pts = [p+0 for p in pts]
	else: raise Exception('\n[ERROR] unclear bilayer topography: %s'%shape)
	#---previously used PBCs and selected the middle tile here before makemesh and then shifted to origin
	monolayer_meshes = [makemesh(p,vecs,debug=False,curvilinear=False) for p in pts]
	return pts,monolayer_meshes,array([v for v in vecs]+[lz])
Exemple #3
0
def makeshape():
    """
	Generate the midplane points for various bilayer shapes.
	"""

    shape = wordspace['shape']
    lz = wordspace['solvent_thickness']
    binsize = wordspace['binsize']
    #---are the monolayers symmetric?
    monolayer_other = wordspace.get('monolayer_other', None)
    composition_other = wordspace.get('composition_other', None)
    if not monolayer_other and composition_other or not composition_other and monolayer_other:
        raise Exception(
            'you must specify both "monolayer other" and "composition other"')
    monolayers = [[wordspace['monolayer_top'], wordspace['composition_top']]]
    if monolayer_other: monolayers += [[monolayer_other, composition_other]]
    else: monolayers += [monolayers[0]]
    #---compute spots on the 2D grid where we will place the lipids
    #---! note that we are still in 2D so the grid-spacing is only accurate for the flat bilayer
    spots, vecs = zip(*[
        random_lipids(total, composition, binsize)
        for total, composition in monolayers
    ])
    #---for asymmetric bilayers we choose the larger set of box vectors
    vecs = transpose([max(i) for i in transpose(vecs)])
    pts = [
        np.concatenate(([s[:, 0]], [s[:, 1]], [np.zeros(len(s))])).T
        for s in spots
    ]
    #---! non-flat points will be stretched in Z hence not evenly spaced in 3-space
    #---! needs 2 monolayers
    if shape == 'saddle':

        def bump(x, y, x0, y0, height, width):
            """
			General function for producing a 2D Gaussian "dimple" or "bump".
			"""
            zs = height*np.exp(-(x-x0)**2/2/width**2)*\
             np.exp(-(y-y0)**2/2/width**2)
            return zs

        offsets = vecs[:2] / 2. - 2.
        bumpspots = [(0, 1, 1), (0, -1, 1), (1, 0, -1), (-1, 0, -1)]
        for spot in bumpspots:
            pts[:,
                2] += bump(xys[:, 0], xys[:, 1], x0 + offsets[0] * spot[0],
                           y0 + offsets[1] * spot[1], height * spot[2], width)
        ptsmid = np.concatenate(
            np.reshape(pts, (3 * m, 3 * n, 3))[m:2 * m, n:2 * n])
        ptsmid[:, 0] -= vecs[0]
        ptsmid[:, 1] -= vecs[1]

        if 0: meshplot(ptsmid, show='surf')

    #---! needs 2 monolayers
    elif shape == 'buckle':

        def buckle(x, y, height):
            zs = height * np.sin(x * 2 * pi / lx)
            return zs

        pts[:, 2] += buckle(xys[:, 0], xys[:, 1], height)

    elif shape == 'flat':
        pts = [p + 0 for p in pts]
    else:
        raise Exception('\n[ERROR] unclear bilayer topography: %s' % shape)
    #---previously used PBCs and selected the middle tile here before makemesh and then shifted to origin
    monolayer_meshes = [
        makemesh(p, vecs, debug=False, curvilinear=False) for p in pts
    ]
    return pts, monolayer_meshes, array([v for v in vecs] + [lz])
Exemple #4
0
def trim_waters(structure='solvate-dense',gro='solvate',
	gap=3,boxvecs=None,method='aamd',boxcut=True):

	"""
	trim_waters(structure='solvate-dense',gro='solvate',gap=3,boxvecs=None)
	Remove waters within a certain number of Angstroms of the protein.
	#### water and all (water and (same residue as water within 10 of not water))
	note that we vided the solvate.gro as a default so this can be used with any output gro file
	"""

	use_vmd = wordspace.get('use_vmd',False)
	if (gap != 0.0 or boxcut) and use_vmd:
		if method == 'aamd': watersel = "water"
		elif method == 'cgmd': watersel = "resname %s"%wordspace.sol
		else: raise Exception("\n[ERROR] unclear method %s"%method)
		#---! gap should be conditional and excluded if zero
		vmdtrim = [
			'package require pbctools',
			'mol new %s.gro'%structure,
			'set sel [atomselect top \"(all not ('+\
			'%s and (same residue as %s and within '%(watersel,watersel)+str(gap)+\
			' of not %s)))'%watersel]
		#---box trimming is typical for e.g. atomstic protein simulations but discards anything outside
		if boxcut:
			vmdtrim += [' and '+\
			'same residue as (x>=0 and x<='+str(10*boxvecs[0])+\
			' and y>=0 and y<= '+str(10*boxvecs[1])+\
			' and z>=0 and z<= '+str(10*boxvecs[2])+')']
		vmdtrim += ['"]','$sel writepdb %s-vmd.pdb'%gro,'exit',]			
		with open(wordspace['step']+'script-vmd-trim.tcl','w') as fp:
			for line in vmdtrim: fp.write(line+'\n')
		vmdlog = open(wordspace['step']+'log-script-vmd-trim','w')
		#---previously used os.environ['VMDNOCUDA'] = "1" but this was causing segfaults on green
		p = subprocess.Popen('VMDNOCUDA=1 '+gmxpaths['vmd']+' -dispdev text -e script-vmd-trim.tcl',
			stdout=vmdlog,stderr=vmdlog,cwd=wordspace['step'],shell=True,executable='/bin/bash')
		p.communicate()
		with open(wordspace['bash_log'],'a') as fp:
			fp.write(gmxpaths['vmd']+' -dispdev text -e script-vmd-trim.tcl &> log-script-vmd-trim\n')
		gmx_run(gmxpaths['editconf']+' -f %s-vmd.pdb -o %s.gro -resnr 1'%(gro,gro),
			log='editconf-convert-vmd')
	#---scipy is more reliable than VMD
	elif gap != 0.0 or boxcut:
		import scipy
		import scipy.spatial
		import numpy as np
		#---if "sol" is not in the wordspace we assume this is atomistic and use the standard "SOL"
		watersel = wordspace.get('sol','SOL')
		incoming = read_gro(structure+'.gro')
		#---remove waters that are near not-waters
		is_water = np.array(incoming['residue_names'])==watersel
		is_not_water = np.array(incoming['residue_names'])!=watersel
		water_inds = np.where(is_water)[0]
		not_water_inds = np.where(np.array(incoming['residue_names'])!=watersel)[0]
		points = np.array(incoming['points'])
		residue_indices = np.array(incoming['residue_indices'])
		if gap>0:
			#---previous method used clumsy/slow cdist
			if False:
				#---! needs KDTree optimization
				dists = scipy.spatial.distance.cdist(points[water_inds],points[not_water_inds])
				#---list of residue indices in is_water that have at least one atom with an overlap
				excludes = np.array(incoming['residue_indices'])[is_water][
					np.where(np.any(dists<=gap/10.0,axis=1))[0]]
				#---collect waters not found in the excludes list of residues that overlap with not-water
				#---note that this command fails on redundant residues
				#---this was deprecated because it wasn't working correctly with the new KDTree method below
				surviving_water = np.all((np.all((
					np.tile(excludes,(len(residue_indices),1))!=np.tile(residue_indices,(len(excludes),1)).T),
					axis=1),is_water),axis=0)
			#---use scipy KDTree to find atom names inside the gap
			#---note that order matters: we wish to find waters too close to not_waters
			close_dists,neighbors = scipy.spatial.KDTree(points[water_inds]).query(points[not_water_inds],distance_upper_bound=gap/10.0)
			#---use the distances to find the residue indices for waters that are too close 
			excludes = np.array(incoming['residue_indices'])[is_water][np.where(close_dists<=gap/10.0)[0]]
			#---get residues that are water and in the exclude list
			#---note that the following step might be slow
			exclude_res = [ii for ii,i in enumerate(incoming['residue_indices']) if i in excludes and is_water[ii]]
			#---copy the array that marks the waters
			surviving_water = np.array(is_water)
			#---remove waters that are on the exclude list
			surviving_water[exclude_res] = False
		else: 
			excludes = np.array([])
			surviving_water = np.ones(len(residue_indices)).astype(bool)
		#---we must remove waters that lie outside the box if there is a boxcut
		insiders = np.ones(len(points)).astype(bool)
		if boxcut:
			#---remove waters that lie outside the box
			#---get points that are outside of the box
			outsiders = np.any([np.any((points[:,ii]<0,points[:,ii]>i),axis=0) 
				for ii,i in enumerate(boxvecs)],axis=0)
			#---get residue numbers for the outsiders
			outsiders_res = np.array(incoming['residue_indices'])[np.where(outsiders)[0]]
			#---note that this is consonant with the close-water exclude step above (and also may be slow)
			exclude_outsider_res = [ii for ii,i in 
				enumerate(incoming['residue_indices']) if i in outsiders_res]
			insiders[exclude_outsider_res] = False
		surviving_indices = np.any((is_not_water,np.all((surviving_water,insiders),axis=0)),axis=0)
		lines = incoming['lines']
		lines = lines[:2]+list(np.array(incoming['lines'][2:-1])[surviving_indices])+lines[-1:]
		xyzs = list(points[surviving_indices])
		write_gro(lines=lines,xyzs=xyzs,output_file=wordspace.step+'%s.gro'%gro)
	else: filecopy(wordspace['step']+'%s-dense.gro'%gro,wordspace['step']+'%s.gro'%gro)
Exemple #5
0
def counterions(structure,
                top,
                includes=None,
                ff_includes=None,
                gro='counterions'):
    """
	counterions(structure,top)
	Standard procedure for adding counterions.
	The resname must be understandable by "r RESNAME" in make_ndx and writes to the top file.
	"""

    #---we store the water resname in the wordspace as "sol"
    resname = wordspace.get('sol', 'SOL')
    #---clean up the composition in case this is a restart
    for key in ['cation', 'anion', resname]:
        try:
            wordspace['composition'].pop(
                zip(*wordspace['composition'])[0].index(wordspace[key]))
        except:
            pass
    component(resname, count=wordspace['water_without_ions'])
    #---write the topology file as of the solvate step instead of copying them (genion overwrites top)
    write_top('counterions.top')
    gmx('grompp',
        base='genion',
        structure=structure,
        top='counterions',
        mdp='input-em-steep-in',
        log='grompp-genion')
    gmx('make_ndx',
        structure=structure,
        ndx='solvate-waters',
        inpipe='keep 0\nr %s\nkeep 1\nq\n' % resname,
        log='make-ndx-counterions-check')
    gmx('genion',
        base='genion',
        gro=gro,
        ndx='solvate-waters',
        cation=wordspace['cation'],
        anion=wordspace['anion'],
        flag='-conc %f -neutral' % wordspace['ionic_strength'],
        log='genion')
    with open(wordspace['step'] + 'log-genion', 'r') as fp:
        lines = fp.readlines()
    declare_ions = filter(lambda x: re.search('Will try', x) != None,
                          lines).pop()
    ion_counts = re.findall(
        '^Will try to add ([0-9]+)\+?\-? ([\w\+\-]+) ions and ([0-9]+) ([\w\+\-]+) ions',
        declare_ions).pop()
    for ii in range(2):
        component(ion_counts[2 * ii + 1], count=ion_counts[2 * ii])
    component(resname,
              count=component(resname) - component(ion_counts[1]) -
              component(ion_counts[3]))
    if includes:
        if type(includes) == str: includes = [includes]
        for i in includes:
            include(i)
    if ff_includes:
        if type(ff_includes) == str: ff_includes = [ff_includes]
        for i in ff_includes:
            include(i, ff=True)
    write_top('counterions.top')
Exemple #6
0
def trim_waters(structure='solvate-dense',
                gro='solvate',
                gap=3,
                boxvecs=None,
                method='aamd',
                boxcut=True):
    """
	trim_waters(structure='solvate-dense',gro='solvate',gap=3,boxvecs=None)
	Remove waters within a certain number of Angstroms of the protein.
	#### water and all (water and (same residue as water within 10 of not water))
	note that we vided the solvate.gro as a default so this can be used with any output gro file
	"""

    use_vmd = wordspace.get('use_vmd', False)
    if (gap != 0.0 or boxcut) and use_vmd:
        if method == 'aamd': watersel = "water"
        elif method == 'cgmd': watersel = "resname %s" % wordspace.sol
        else: raise Exception("\n[ERROR] unclear method %s" % method)
        #---! gap should be conditional and excluded if zero
        vmdtrim = [
         'package require pbctools',
         'mol new %s.gro'%structure,
         'set sel [atomselect top \"(all not ('+\
         '%s and (same residue as %s and within '%(watersel,watersel)+str(gap)+\
         ' of not %s)))'%watersel]
        #---box trimming is typical for e.g. atomstic protein simulations but discards anything outside
        if boxcut:
            vmdtrim += [' and '+\
            'same residue as (x>=0 and x<='+str(10*boxvecs[0])+\
            ' and y>=0 and y<= '+str(10*boxvecs[1])+\
            ' and z>=0 and z<= '+str(10*boxvecs[2])+')']
        vmdtrim += [
            '"]',
            '$sel writepdb %s-vmd.pdb' % gro,
            'exit',
        ]
        with open(wordspace['step'] + 'script-vmd-trim.tcl', 'w') as fp:
            for line in vmdtrim:
                fp.write(line + '\n')
        vmdlog = open(wordspace['step'] + 'log-script-vmd-trim', 'w')
        #---previously used os.environ['VMDNOCUDA'] = "1" but this was causing segfaults on green
        p = subprocess.Popen('VMDNOCUDA=1 ' + gmxpaths['vmd'] +
                             ' -dispdev text -e script-vmd-trim.tcl',
                             stdout=vmdlog,
                             stderr=vmdlog,
                             cwd=wordspace['step'],
                             shell=True,
                             executable='/bin/bash')
        p.communicate()
        with open(wordspace['bash_log'], 'a') as fp:
            fp.write(
                gmxpaths['vmd'] +
                ' -dispdev text -e script-vmd-trim.tcl &> log-script-vmd-trim\n'
            )
        gmx_run(gmxpaths['editconf'] + ' -f %s-vmd.pdb -o %s.gro -resnr 1' %
                (gro, gro),
                log='editconf-convert-vmd')
    #---scipy is more reliable than VMD
    elif gap != 0.0 or boxcut:
        import scipy
        import scipy.spatial
        import numpy as np
        #---if "sol" is not in the wordspace we assume this is atomistic and use the standard "SOL"
        watersel = wordspace.get('sol', 'SOL')
        incoming = read_gro(structure + '.gro')
        #---remove waters that are near not-waters
        is_water = np.array(incoming['residue_names']) == watersel
        is_not_water = np.array(incoming['residue_names']) != watersel
        water_inds = np.where(is_water)[0]
        not_water_inds = np.where(
            np.array(incoming['residue_names']) != watersel)[0]
        points = np.array(incoming['points'])
        residue_indices = np.array(incoming['residue_indices'])
        if gap > 0:
            #---previous method used clumsy/slow cdist
            if False:
                #---! needs KDTree optimization
                dists = scipy.spatial.distance.cdist(points[water_inds],
                                                     points[not_water_inds])
                #---list of residue indices in is_water that have at least one atom with an overlap
                excludes = np.array(
                    incoming['residue_indices'])[is_water][np.where(
                        np.any(dists <= gap / 10.0, axis=1))[0]]
                #---collect waters not found in the excludes list of residues that overlap with not-water
                #---note that this command fails on redundant residues
                #---this was deprecated because it wasn't working correctly with the new KDTree method below
                surviving_water = np.all((np.all(
                    (np.tile(excludes, (len(residue_indices), 1)) != np.tile(
                        residue_indices, (len(excludes), 1)).T),
                    axis=1), is_water),
                                         axis=0)
            #---use scipy KDTree to find atom names inside the gap
            #---note that order matters: we wish to find waters too close to not_waters
            close_dists, neighbors = scipy.spatial.KDTree(
                points[water_inds]).query(points[not_water_inds],
                                          distance_upper_bound=gap / 10.0)
            #---use the distances to find the residue indices for waters that are too close
            excludes = np.array(
                incoming['residue_indices'])[is_water][np.where(
                    close_dists <= gap / 10.0)[0]]
            #---get residues that are water and in the exclude list
            #---note that the following step might be slow
            exclude_res = [
                ii for ii, i in enumerate(incoming['residue_indices'])
                if i in excludes and is_water[ii]
            ]
            #---copy the array that marks the waters
            surviving_water = np.array(is_water)
            #---remove waters that are on the exclude list
            surviving_water[exclude_res] = False
        else:
            excludes = np.array([])
            surviving_water = np.ones(len(residue_indices)).astype(bool)
        #---we must remove waters that lie outside the box if there is a boxcut
        insiders = np.ones(len(points)).astype(bool)
        if boxcut:
            #---remove waters that lie outside the box
            #---get points that are outside of the box
            outsiders = np.any([
                np.any((points[:, ii] < 0, points[:, ii] > i), axis=0)
                for ii, i in enumerate(boxvecs)
            ],
                               axis=0)
            #---get residue numbers for the outsiders
            outsiders_res = np.array(
                incoming['residue_indices'])[np.where(outsiders)[0]]
            #---note that this is consonant with the close-water exclude step above (and also may be slow)
            exclude_outsider_res = [
                ii for ii, i in enumerate(incoming['residue_indices'])
                if i in outsiders_res
            ]
            insiders[exclude_outsider_res] = False
        surviving_indices = np.any(
            (is_not_water, np.all((surviving_water, insiders), axis=0)),
            axis=0)
        lines = incoming['lines']
        lines = lines[:2] + list(
            np.array(incoming['lines'][2:-1])[surviving_indices]) + lines[-1:]
        xyzs = list(points[surviving_indices])
        write_gro(lines=lines,
                  xyzs=xyzs,
                  output_file=wordspace.step + '%s.gro' % gro)
    else:
        filecopy(wordspace['step'] + '%s-dense.gro' % gro,
                 wordspace['step'] + '%s.gro' % gro)