Ejemplo n.º 1
0
def bilayer_sorter(structure,ndx='system-groups'):

	"""
	Divide the system into groups.
	"""

	if 'protein_ready' in wordspace:
		gmx('make_ndx',structure=structure,ndx='%s-inspect'%structure,
			log='make-ndx-%s-inspect'%structure,inpipe="q\n")
		with open(wordspace['step']+'log-make-ndx-%s-inspect'%structure) as fp: lines = fp.readlines()
		#---find the protein group because it may not be obvious in CGMD
		make_ndx_sifter = '^\s*([0-9]+)\s*Protein'
		protein_group = int(re.findall(make_ndx_sifter,
			next(i for i in lines if re.match(make_ndx_sifter,i)))[0])
		group_selector = "\n".join([
			"keep %s"%protein_group,
			"name 0 PROTEIN",
			#---! hacked
			" || ".join(['r '+r for r in wordspace['lipids']+['PIP2']]),
			"name 1 LIPIDS",
			" || ".join(['r '+r for r in ['W','ION',wordspace['cation'],wordspace['anion']]]),
			"name 2 SOLVENT",
			"0 | 1 | 2","name 3 SYSTEM","q"])+"\n"
	else:
		group_selector = "\n".join([
			"keep 0",
			"name 0 SYSTEM",
			" || ".join(['r '+r for r in wordspace['lipids']]),
			"name 1 LIPIDS",
			" || ".join(['r '+r for r in ['W','ION',wordspace['cation'],wordspace['anion']]]),
			"name 2 SOLVENT","q"])+"\n"
	gmx('make_ndx',structure='system',ndx=ndx,log='make-ndx-groups',
		inpipe=group_selector)
Ejemplo n.º 2
0
def vacuum_pack(structure='vacuum',
                name='vacuum-pack',
                gro='vacuum-packed',
                pbc='nojump'):
    """
	Pack the lipids in the plane, gently.
	"""

    gmx('grompp',
        base='md-%s' % name,
        top='vacuum',
        structure=structure,
        log='grompp-%s' % name,
        mdp='input-md-%s-eq-in' % name,
        flag='-maxwarn 100')
    gmx('mdrun', base='md-%s' % name, log='mdrun-%s' % name, skip=True)
    if pbc:
        remove_jump(structure='md-%s' % name,
                    tpr='md-' + name,
                    gro='md-%s-%s' % (name, pbc))
        filecopy(wordspace['step'] + 'md-%s-%s.gro' % (name, pbc),
                 wordspace['step'] + '%s.gro' % gro)
    else:
        filecopy(wordspace['step'] + 'md-%s' % gro,
                 wordspace['step'] + '%s.gro' % gro)
    boxdims_old, boxdims = get_box_vectors(gro)
    wordspace['bilayer_dimensions_slab'][:2] = boxdims_old[:2]
Ejemplo n.º 3
0
def get_box_vectors(structure,gro=None,d=0,log='checksize'):

	"""
	Return the box vectors.
	"""

	if not gro: gro = structure+'-check-box'
	#---note that we consult the command_library here
	gmx('editconf',structure=structure,gro=gro,
		log='editconf-%s'%log,flag='-d %d'%d)
	with open(wordspace['step']+'log-editconf-%s'%log,'r') as fp: lines = fp.readlines()
	box_vector_regex = '\s*box vectors\s*\:\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)'
	box_vector_new_regex = '\s*new box vectors\s*\:\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)'
	runon_regex = '^\s*([-]?[0-9]+\.?[0-9]{0,3})\s*([-]?[0-9]+\.?[0-9]{0,3})\s*([-]?[0-9]+\.?[0-9]{0,3})'
	old_line = [l for l in lines if re.match(box_vector_regex,l)][0]
	vecs_old = re.findall('\s*box vectors\s*:([^\(]+)',old_line)[0]
	try:
		#---sometimes the numbers run together
		try: vecs_old = [float(i) for i in vecs_old.strip(' ').split()]
		except: vecs_old = [float(i) for i in re.findall(runon_regex,vecs_old)[0]]
		#---repeat for new box vectors
		new_line = [l for l in lines if re.match(box_vector_new_regex,l)][0]
		vecs_new = re.findall('\s*box vectors\s*:([^\(]+)',new_line)[0]
		try: vecs_new = [float(i) for i in vecs_new.strip(' ').split()]
		except: vecs_new = [float(i) for i in re.findall(runon_regex,vecs_new)[0]]
	except:
		import pdb;pdb.set_trace()
	#---no need to keep the output since it is a verbatim copy for diagnostic only
	os.remove(wordspace['step']+gro+'.gro')
	#import pdb;pdb.set_trace()
	return vecs_old,vecs_new
Ejemplo n.º 4
0
def remove_jump(structure,tpr,gro):

	"""
	Correct that thing where the bilayer crosses the PBCs and gets split.
	"""

	gmx('make_ndx',ndx=structure,structure=structure,inpipe="keep 0\nq\n",log='make-ndx-nojump')	
	gmx('trjconv',ndx=structure,structure=structure,gro=gro,tpr=tpr,
		log='trjconv-%s-nojump'%structure,flag='-pbc nojump')
	os.remove(wordspace['step']+'log-'+'make-ndx-nojump')
Ejemplo n.º 5
0
def solvate_bilayer(structure='vacuum'):
	
	"""
	Solvate a CGMD bilayer (possibly with proteins) avoiding overlaps.
	"""

	#---check the size of the slab
	incoming_structure = str(structure)
	boxdims_old,boxdims = get_box_vectors(structure)

	#---! standardize these?
	basedim = 3.64428
	waterbox = 'inputs/martini-water'

	#---make an oversized water box
	newdims = boxdims_old[:2]+[wordspace['solvent_thickness']]
	#import pdb;pdb.set_trace()
	gmx('genconf',structure='martini-water',gro='solvate-empty-uncentered-untrimmed',
		nbox=' '.join([str(int(i/basedim+1)) for i in newdims]),log='genconf')

	#---trimming waters
	with open(wordspace['step']+'solvate-empty-uncentered-untrimmed.gro','r') as fp:
		lines = fp.readlines()
	modlines = []
	for line in lines[2:-1]:
		coords = [float(i) for i in line[20:].split()][:3]
		if all([coords[i]<newdims[i] for i in range(3)]): modlines.append(line)
	with open(wordspace['step']+'solvate-empty-uncentered.gro','w') as fp:
		fp.write(lines[0])
		fp.write(str(len(modlines))+'\n')
		for l in modlines: fp.write(l)
		fp.write(lines[-1])

	#---update waters
	structure='solvate-empty-uncentered'
	component('W',count=count_molecules(structure,'W'))
	#---translate the water box
	gmx('editconf',structure=structure,gro='solvate-water-shifted',
		flag='-translate 0 0 %f'%(wordspace['bilayer_dimensions_slab'][2]/2.),log='editconf-solvate-shift')

	#---combine and trim with new box vectors
	#---! skipping minimization?
	structure = 'solvate-water-shifted'
	boxdims_old,boxdims = get_box_vectors(structure)
	boxvecs = wordspace['bilayer_dimensions_slab'][:2]+[wordspace['bilayer_dimensions_slab'][2]+boxdims[2]]
	gro_combinator('%s.gro'%incoming_structure,structure,box=boxvecs,
		cwd=wordspace['step'],gro='solvate-dense')
	structure = 'solvate-dense'
	trim_waters(structure=structure,gro='solvate',boxcut=False,
		gap=wordspace['protein_water_gap'],method='cgmd',boxvecs=boxvecs)
	structure = 'solvate'
	nwaters = count_molecules(structure,'W')
	component('W',count=nwaters)
	wordspace['bilayer_dimensions_solvate'] = boxvecs
	wordspace['water_without_ions'] = nwaters
Ejemplo n.º 6
0
def equilibrate(groups=None,structure='system'):

	"""
	equilibrate()
	Standard equilibration procedure.
	"""

	#---sequential equilibration stages
	seq = wordspace.equilibration.split(',') if wordspace.equilibration else []
	for eqnum,name in enumerate(seq):
		if not equilibrate_check(name):
			gmx('grompp',base='md-%s'%name,top='system',
				structure=structure if eqnum == 0 else 'md-%s'%seq[eqnum-1],
				log='grompp-%s'%name,mdp='input-md-%s-eq-in'%name,
				flag=('' if not groups else '-n %s'%groups)+' -maxwarn 10')
			gmx('mdrun',base='md-%s'%name,log='mdrun-%s'%name,skip=True)
			assert os.path.isfile(wordspace['step']+'md-%s.gro'%name)
			checkpoint()

	#---first part of the equilibration/production run
	name = 'md.part0001'
	if not equilibrate_check(name) or seq == []:
		gmx('grompp',base=name,top='system',
			structure='md-%s'%seq[-1] if seq else structure,
			log='grompp-0001',mdp='input-md-in',
			flag='' if not groups else '-n %s'%groups)
		gmx('mdrun',base=name,log='mdrun-0001')
		#---we don't assert that the file exists here because the user might kill it and upload
		checkpoint()
Ejemplo n.º 7
0
def minimize(name,method='steep',top=None):

	"""
	minimize(name,method='steep')
	Standard minimization procedure.
	"""

	gmx('grompp',base='em-%s-%s'%(name,method),top=name if not top else re.sub('^(.+)\.top$',r'\1',top),
		structure=name,log='grompp-%s-%s'%(name,method),mdp='input-em-%s-in'%method,skip=True)
	assert os.path.isfile(wordspace['step']+'em-%s-%s.tpr'%(name,method))
	gmx('mdrun',base='em-%s-%s'%(name,method),log='mdrun-%s-%s'%(name,method))
	filecopy(wordspace['step']+'em-'+'%s-%s.gro'%(name,method),
		wordspace['step']+'%s-minimized.gro'%name)
	checkpoint()
Ejemplo n.º 8
0
def count_molecules(structure,resname):

	"""
	Count the number of molecules in a system using make_ndx.
	"""

	gmx('make_ndx',structure=structure,ndx=structure+'-count',
		log='make-ndx-%s-check'%structure,inpipe='q\n')
	with open(wordspace['step']+'log-make-ndx-%s-check'%structure) as fp: lines = fp.readlines()
	try:
		residue_regex = '^\s*[0-9]+\s+%s\s+\:\s+([0-9]+)\s'%resname
		count, = [int(re.findall(residue_regex,l)[0]) for l in lines if re.match(residue_regex,l)]
	except: raise Exception('cannot find resname "%s" in %s'%(resname,'make-ndx-%s-check'%structure))
	return count
Ejemplo n.º 9
0
def minimize_steep_cg(name):
    """
	minimize_steep_cg(name)
	Minimization using steepest descent followed by conjugate gradient.
	Note that this method has been retired due to reliability issues.
	"""

    gmx('grompp',
        base='em-%s-steep' % name,
        top=name,
        structure=name,
        log='grompp-em-%s-steep' % name,
        mdp='input-em-steep-in')
    gmx('mdrun',
        base='em-%s-steep' % name,
        log='mdrun-%s-steep' % name,
        skip=True)
    #---if first step fails we skip it and try again with the second minimizer
    if not os.path.isfile(wordspace['step'] + 'em-%s-steep.gro'):
        filecopy(wordspace['step'] + '%s.gro' % name,
                 wordspace['step'] + 'em-%s-steep.gro' % name)
    gmx('grompp',
        base='em-%s-cg' % name,
        top=name,
        structure='em-%s-steep' % name,
        log='grompp-%s-cg' % name,
        mdp='input-em-cg-in',
        skip=True)
    gmx('mdrun', base='em-%s-cg' % name, log='mdrun-%s-cg' % name)
    select_minimum('%s-steep' % name,
                   '%s-cg' % name,
                   gro='%s-minimized' % name)
    checkpoint()
Ejemplo n.º 10
0
def equilibrate(groups=None, structure='system'):
    """
	equilibrate()
	Standard equilibration procedure.
	"""

    #---sequential equilibration stages
    seq = wordspace.equilibration.split(',') if wordspace.equilibration else []
    for eqnum, name in enumerate(seq):
        if not equilibrate_check(name):
            gmx('grompp',
                base='md-%s' % name,
                top='system',
                structure=structure if eqnum == 0 else 'md-%s' %
                seq[eqnum - 1],
                log='grompp-%s' % name,
                mdp='input-md-%s-eq-in' % name,
                flag=('' if not groups else '-n %s' % groups) + ' -maxwarn 10')
            gmx('mdrun', base='md-%s' % name, log='mdrun-%s' % name, skip=True)
            assert os.path.isfile(wordspace['step'] + 'md-%s.gro' % name)
            checkpoint()

    #---first part of the equilibration/production run
    name = 'md.part0001'
    if not equilibrate_check(name) or seq == []:
        gmx('grompp',
            base=name,
            top='system',
            structure='md-%s' % seq[-1] if seq else structure,
            log='grompp-0001',
            mdp='input-md-in',
            flag='' if not groups else '-n %s' % groups)
        gmx('mdrun', base=name, log='mdrun-0001')
        #---we don't assert that the file exists here because the user might kill it and upload
        checkpoint()
Ejemplo n.º 11
0
def vacuum_pack(structure='vacuum',name='vacuum-pack',gro='vacuum-packed'):

	"""
	Pack the lipids in the plane, gently.
	"""

	gmx('grompp',base='md-%s'%name,top='vacuum',
		structure=structure,log='grompp-%s'%name,mdp='input-md-%s-eq-in'%name,
		flag='-maxwarn 100')
	gmx('mdrun',base='md-%s'%name,log='mdrun-%s'%name,skip=True)
	remove_jump(structure='md-%s'%name,tpr='md-'+name,gro='md-%s-nojump'%name)
	filecopy(wordspace['step']+'md-%s-nojump.gro'%name,wordspace['step']+'%s.gro'%gro)
	boxdims_old,boxdims = get_box_vectors(gro)
	wordspace['bilayer_dimensions_slab'][:2] = boxdims_old[:2]
Ejemplo n.º 12
0
def bilayer_sorter(structure, ndx='system-groups'):
    """
	Divide the system into groups.
	"""

    if 'protein_ready' in wordspace:
        gmx('make_ndx',
            structure=structure,
            ndx='%s-inspect' % structure,
            log='make-ndx-%s-inspect' % structure,
            inpipe="q\n")
        with open(wordspace['step'] +
                  'log-make-ndx-%s-inspect' % structure) as fp:
            lines = fp.readlines()
        #---find the protein group because it may not be obvious in CGMD
        make_ndx_sifter = '^\s*([0-9]+)\s*Protein'
        protein_group = int(
            re.findall(make_ndx_sifter,
                       next(i for i in lines
                            if re.match(make_ndx_sifter, i)))[0])
        group_selector = "\n".join([
            "keep %s" % protein_group,
            "name 0 PROTEIN",
            #---! hacked
            " || ".join(['r ' + r for r in wordspace['lipids'] + ['PIP2']]),
            "name 1 LIPIDS",
            " || ".join([
                'r ' + r
                for r in ['W', 'ION', wordspace['cation'], wordspace['anion']]
            ]),
            "name 2 SOLVENT",
            "0 | 1 | 2",
            "name 3 SYSTEM",
            "q"
        ]) + "\n"
    else:
        group_selector = "\n".join([
            "keep 0", "name 0 SYSTEM", " || ".join([
                'r ' + r for r in wordspace['lipids']
            ]), "name 1 LIPIDS", " || ".join([
                'r ' + r
                for r in ['W', 'ION', wordspace['cation'], wordspace['anion']]
            ]), "name 2 SOLVENT", "q"
        ]) + "\n"
    gmx('make_ndx',
        structure='system',
        ndx=ndx,
        log='make-ndx-groups',
        inpipe=group_selector)
Ejemplo n.º 13
0
def solvate_bilayer(structure='vacuum'):
	
	"""
	Solvate a CGMD bilayer (possibly with proteins) avoiding overlaps.
	"""

	#---check the size of the slab
	incoming_structure = str(structure)
	boxdims_old,boxdims = get_box_vectors(structure)
	#---check the size of the water box
	waterbox = wordspace.water_box
	basedim,_ = get_box_vectors(waterbox)
	if not all([i==basedim[0] for i in basedim]):
		raise Exception('[ERROR] expecting water box "" to be cubic')
	else: basedim = basedim[0]
	#---make an oversized water box
	newdims = boxdims_old[:2]+[wordspace['solvent_thickness']]
	gmx('genconf',structure=waterbox,gro='solvate-empty-uncentered-untrimmed',
		nbox=' '.join([str(int(i/basedim+1)) for i in newdims]),log='genconf')
	#---trim the blank water box
	trim_waters(structure='solvate-empty-uncentered-untrimmed',
		gro='solvate-empty-uncentered',boxcut=True,boxvecs=newdims,
		gap=0.0,method=wordspace.atom_resolution)
	#---update waters
	structure='solvate-empty-uncentered'
	component(wordspace.sol,count=count_molecules(structure,wordspace.sol))
	#---translate the water box
	gmx('editconf',structure=structure,gro='solvate-water-shifted',
		flag='-translate 0 0 %f'%(wordspace['bilayer_dimensions_slab'][2]/2.),log='editconf-solvate-shift')
	#---combine and trim with new box vectors
	structure = 'solvate-water-shifted'
	boxdims_old,boxdims = get_box_vectors(structure)
	boxvecs = wordspace['bilayer_dimensions_slab'][:2]+[wordspace['bilayer_dimensions_slab'][2]+boxdims[2]]
	gro_combinator('%s.gro'%incoming_structure,structure,box=boxvecs,
		cwd=wordspace['step'],gro='solvate-dense')
	structure = 'solvate-dense'
	#---trim everything so that waters are positioned in the box without steric clashes
	trim_waters(structure=structure,gro='solvate',boxcut=False,
		gap=wordspace['protein_water_gap'],method=wordspace.atom_resolution,boxvecs=boxvecs)
	structure = 'solvate'
	nwaters = count_molecules(structure,wordspace.sol)/({'aamd':3.0,'cgmd':1.0}[wordspace.atom_resolution])
	if round(nwaters)!=nwaters: raise Exception('[ERROR] fractional water molecules')
	else: nwaters = int(nwaters)
	component(wordspace.sol,count=nwaters)
	wordspace['bilayer_dimensions_solvate'] = boxvecs
	wordspace['water_without_ions'] = nwaters
Ejemplo n.º 14
0
def remove_jump(structure, tpr, gro):
    """
	Correct that thing where the bilayer crosses the PBCs and gets split.
	"""

    gmx('make_ndx',
        ndx=structure,
        structure=structure,
        inpipe="keep 0\nq\n",
        log='make-ndx-nojump')
    gmx('trjconv',
        ndx=structure,
        structure=structure,
        gro=gro,
        tpr=tpr,
        log='trjconv-%s-nojump' % structure,
        flag='-pbc nojump')
    os.remove(wordspace['step'] + 'log-' + 'make-ndx-nojump')
Ejemplo n.º 15
0
def minimize(name, method='steep', top=None):
    """
	minimize(name,method='steep')
	Standard minimization procedure.
	"""

    gmx('grompp',
        base='em-%s-%s' % (name, method),
        top=name if not top else re.sub('^(.+)\.top$', r'\1', top),
        structure=name,
        log='grompp-%s-%s' % (name, method),
        mdp='input-em-%s-in' % method,
        skip=True)
    assert os.path.isfile(wordspace['step'] + 'em-%s-%s.tpr' % (name, method))
    gmx('mdrun',
        base='em-%s-%s' % (name, method),
        log='mdrun-%s-%s' % (name, method))
    filecopy(wordspace['step'] + 'em-' + '%s-%s.gro' % (name, method),
             wordspace['step'] + '%s-minimized.gro' % name)
    checkpoint()
Ejemplo n.º 16
0
def bilayer_middle(structure, gro):
    """
	Move the bilayer to the middle of the z-coordinate of the box.
	Note that the protein adhesion procedure works best on a slab that is centered on z=0.
	This means that the bilayer will be broken across z=0.
	For visualization it is better to center it.
	"""

    gmx('make_ndx',
        ndx='system-dry',
        structure='counterions-minimized',
        inpipe="keep 0\nr %s || r ION || r %s || r %s\n!1\ndel 1\nq\n" %
        (wordspace['sol'], wordspace['anion'], wordspace['cation']),
        log='make-ndx-center')
    #---bilayer slab is near z=0 so it is likely split so we shift by half of the box vector
    gmx('trjconv',
        structure='counterions-minimized',
        gro='counterions-shifted',
        ndx='system-dry',
        flag='-trans 0 0 %f -pbc mol' %
        (wordspace['bilayer_dimensions_solvate'][2] / 2.),
        tpr='em-counterions-steep',
        log='trjconv-shift',
        inpipe="0\n")
    #---center everything
    gmx('trjconv',
        structure='counterions-shifted',
        gro='system',
        ndx='system-dry',
        tpr='em-counterions-steep',
        log='trjconv-middle',
        inpipe="1\n0\n",
        flag='-center -pbc mol')
Ejemplo n.º 17
0
def get_box_vectors(structure, gro=None, d=0, log='checksize'):
    """
	Return the box vectors.
	"""

    if not gro: gro = structure + '-check-box'
    #---note that we consult the command_library here
    gmx('editconf',
        structure=structure,
        gro=gro,
        log='editconf-%s' % log,
        flag='-d %d' % d)
    with open(wordspace['step'] + 'log-editconf-%s' % log, 'r') as fp:
        lines = fp.readlines()
    box_vector_regex = '\s*box vectors\s*\:\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)'
    box_vector_new_regex = '\s*new box vectors\s*\:\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)'
    runon_regex = '^\s*([-]?[0-9]+\.?[0-9]{0,3})\s*([-]?[0-9]+\.?[0-9]{0,3})\s*([-]?[0-9]+\.?[0-9]{0,3})'
    old_line = [l for l in lines if re.match(box_vector_regex, l)][0]
    vecs_old = re.findall('\s*box vectors\s*:([^\(]+)', old_line)[0]
    try:
        #---sometimes the numbers run together
        try:
            vecs_old = [float(i) for i in vecs_old.strip(' ').split()]
        except:
            vecs_old = [float(i) for i in re.findall(runon_regex, vecs_old)[0]]
        #---repeat for new box vectors
        new_line = [l for l in lines if re.match(box_vector_new_regex, l)][0]
        vecs_new = re.findall('\s*box vectors\s*:([^\(]+)', new_line)[0]
        try:
            vecs_new = [float(i) for i in vecs_new.strip(' ').split()]
        except:
            vecs_new = [float(i) for i in re.findall(runon_regex, vecs_new)[0]]
    except:
        import pdb
        pdb.set_trace()
    #---no need to keep the output since it is a verbatim copy for diagnostic only
    os.remove(wordspace['step'] + gro + '.gro')
    #import pdb;pdb.set_trace()
    return vecs_old, vecs_new
Ejemplo n.º 18
0
def count_molecules(structure, resname):
    """
	Count the number of molecules in a system using make_ndx.
	"""

    gmx('make_ndx',
        structure=structure,
        ndx=structure + '-count',
        log='make-ndx-%s-check' % structure,
        inpipe='q\n')
    with open(wordspace['step'] + 'log-make-ndx-%s-check' % structure) as fp:
        lines = fp.readlines()
    try:
        residue_regex = '^\s*[0-9]+\s+%s\s+\:\s+([0-9]+)\s' % resname
        count, = [
            int(re.findall(residue_regex, l)[0]) for l in lines
            if re.match(residue_regex, l)
        ]
    except:
        raise Exception('cannot find resname "%s" in %s' %
                        (resname, 'make-ndx-%s-check' % structure))
    return count
Ejemplo n.º 19
0
def minimize_steep_cg(name):

	"""
	minimize_steep_cg(name)
	Minimization using steepest descent followed by conjugate gradient.
	Note that this method has been retired due to reliability issues.
	"""

	gmx('grompp',base='em-%s-steep'%name,top=name,structure=name,
		log='grompp-em-%s-steep'%name,mdp='input-em-steep-in')
	gmx('mdrun',base='em-%s-steep'%name,log='mdrun-%s-steep'%name,skip=True)
	#---if first step fails we skip it and try again with the second minimizer
	if not os.path.isfile(wordspace['step']+'em-%s-steep.gro'):
		filecopy(wordspace['step']+'%s.gro'%name,wordspace['step']+'em-%s-steep.gro'%name)
	gmx('grompp',base='em-%s-cg'%name,top=name,structure='em-%s-steep'%name,
		log='grompp-%s-cg'%name,mdp='input-em-cg-in',skip=True)
	gmx('mdrun',base='em-%s-cg'%name,log='mdrun-%s-cg'%name)
	select_minimum('%s-steep'%name,'%s-cg'%name,gro='%s-minimized'%name)
	checkpoint()
Ejemplo n.º 20
0
def solvate(structure,top):

	"""
	solvate(structure,top)
	Standard solvate procedure for atomistic protein in water.
	"""
	
	#---purge the wordspace of solvent and anions in case we are resuming
	for key in [wordspace['anion'],wordspace['cation'],'SOL']:
		if key in zip(*wordspace['composition'])[0]:
			del wordspace['composition'][zip(*wordspace['composition'])[0].index(key)]
	gmx('editconf',structure=structure,gro='solvate-box-alone',
		log='editconf-checksize',flag='-d 0')
	with open(wordspace['step']+'log-editconf-checksize','r') as fp: lines = fp.readlines()
	boxdims = map(lambda y:float(y),re.findall('\s*box vectors \:\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)',
		filter(lambda x:re.match('\s*box vectors',x),lines).pop()).pop())
	boxvecs = tuple([i+2*wordspace['water_buffer'] for i in boxdims])
	center = tuple([i/2. for i in boxvecs])
	#---cube is not implemented yet
	gmx('editconf',structure=structure,gro='solvate-protein',
		flags='-center %f %f %f'%center+' '+'-box %f %f %f'%boxvecs,
		log='editconf-center-protein')
	gmx('genbox',structure='solvate-protein',solvent=wordspace['solvent'],
		gro='solvate-dense',#top='solvate-standard',
		log='genbox-solvate')
	#---trim waters if the protein_water_gap setting is not False
	if 'protein_water_gap' in wordspace and wordspace['protein_water_gap'] != False:
		trim_waters(structure='solvate-dense',gro='solvate',
			gap=wordspace['protein_water_gap'],boxvecs=boxvecs)
	else: filecopy(wordspace['step']+'solvate-dense.gro',wordspace['step']+'solvate.gro')
	gmx('make_ndx',structure='solvate',ndx='solvate-water-check',inpipe='q\n',
		log='make-ndx-solvate-check')
	with open(wordspace['step']+'log-make-ndx-solvate-check','r') as fp: lines = fp.readlines()
	nwaters = int(re.findall('\s*[0-9]+\s+Water\s+:\s+([0-9]+)\s+atoms',
		filter(lambda x:re.match('\s*[0-9]+\s+Water',x),lines).pop()).pop())/3
	wordspace['water_without_ions'] = nwaters
	component('SOL',count=nwaters)
	#---add the suffix so that water is referred to by its name in the settings
	include(wordspace['water'],ff=True)
	write_top('solvate.top')
Ejemplo n.º 21
0
def bilayer_middle(structure,gro):

	"""
	Move the bilayer to the middle of the z-coordinate of the box.
	Note that the protein adhesion procedure works best on a slab that is centered on z=0.
	This means that the bilayer will be broken across z=0.
	For visualization it is better to center it.
	"""

	gmx('make_ndx',ndx='system-dry',structure='counterions-minimized',
		inpipe="keep 0\nr %s || r ION || r %s || r %s\n!1\ndel 1\nq\n"%(
		wordspace['sol'],wordspace['anion'],wordspace['cation']),
		log='make-ndx-center')
	#---bilayer slab is near z=0 so it is likely split so we shift by half of the box vector
	gmx('trjconv',structure='counterions-minimized',gro='counterions-shifted',ndx='system-dry',
		flag='-trans 0 0 %f -pbc mol'%(wordspace['bilayer_dimensions_solvate'][2]/2.),
		tpr='em-counterions-steep',log='trjconv-shift',inpipe="0\n")
	#---center everything
	gmx('trjconv',structure='counterions-shifted',gro='system',ndx='system-dry',
		tpr='em-counterions-steep',log='trjconv-middle',inpipe="1\n0\n",flag='-center -pbc mol')
Ejemplo n.º 22
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')
Ejemplo n.º 23
0
def write_structure_pdb(structure, pdb):
    """
	write_structure_pdb(structure,pdb)
	Infer the starting residue from the original PDB and write structure.pdb with the correct indices
	according to the latest GRO structure (typically counterions.gro).
	"""

    #---automatically center the protein in the box here and write the final structure
    gmx(
        'make_ndx',
        structure='counterions',
        ndx='counterions-groups',
        log='make-ndx-counterions',
        inpipe='q\n',
    )
    with open(wordspace['step'] + 'log-make-ndx-counterions', 'r') as fp:
        lines = fp.readlines()
    relevant = [
        filter(lambda x: re.match('\s*[0-9]+\s+%s' % name, x), lines)
        for name in ['System', 'Protein']
    ]
    groupdict = dict([
        (j[1], int(j[0])) for j in
        [re.findall('^\s*([0-9]+)\s(\w+)', x[0])[0] for x in relevant]
    ])
    gmx('trjconv',
        ndx='counterions-groups',
        structure='counterions-minimized',
        inpipe='%d\n%d\n' % (groupdict['Protein'], groupdict['System']),
        log='trjconv-counterions-center',
        tpr='em-counterions-steep',
        gro='system')
    with open(wordspace['step'] + pdb, 'r') as fp:
        lines = fp.readlines()
    startres = int([line for line in lines
                    if re.match('^ATOM', line)][0][23:26 + 1])
    gmx('editconf',
        structure=structure,
        flag='-o structure.pdb -resnr %d' % startres,
        log='editconf-structure-pdb')
Ejemplo n.º 24
0
def write_structure_pdb(structure,pdb):

	"""
	write_structure_pdb(structure,pdb)
	Infer the starting residue from the original PDB and write structure.pdb with the correct indices
	according to the latest GRO structure (typically counterions.gro).
	"""

	#---automatically center the protein in the box here and write the final structure
	gmx('make_ndx',structure='counterions',ndx='counterions-groups',
		log='make-ndx-counterions',inpipe='q\n',)
	with open(wordspace['step']+'log-make-ndx-counterions','r') as fp: lines = fp.readlines()
	relevant = [filter(lambda x:re.match('\s*[0-9]+\s+%s'%name,x),lines) for name in ['System','Protein']]
	groupdict = dict([(j[1],int(j[0])) for j in 
		[re.findall('^\s*([0-9]+)\s(\w+)',x[0])[0] for x in relevant]])
	gmx('trjconv',ndx='counterions-groups',structure='counterions-minimized',
		inpipe='%d\n%d\n'%(groupdict['Protein'],groupdict['System']),
		log='trjconv-counterions-center',tpr='em-counterions-steep',gro='system')
	with open(wordspace['step']+pdb,'r') as fp: lines = fp.readlines()
	startres = int([line for line in lines if re.match('^ATOM',line)][0][23:26+1])
	gmx('editconf',structure=structure,
		flag='-o structure.pdb -resnr %d'%startres,
		log='editconf-structure-pdb')
Ejemplo n.º 25
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')
Ejemplo n.º 26
0
def multiply(nx=1,ny=1,nz=1,quirky_ions=True):

	"""
	Make a copy of a simulation box in multiple directions.
	"""

	factor = nx*ny*nz
	#---update the composition
	#---if the last step doesn't have the composition we step backwards and pick up requirements
	#---note that "protein_ready" is important for the bilayer_sorter 
	for prereq in ['composition','lipids','cation','anion','protein_ready']:
		if prereq not in wordspace:
			steplist = detect_last(steplist=True)[::-1]
			#---walk backwards through steps until we find the commposition
			for ii,i in enumerate(steplist):
				oldspace = resume(read_only=True,step=int(re.match('s([0-9]+)-',i).group(1)))
				if prereq in oldspace:
					wordspace[prereq] = deepcopy(oldspace[prereq])
					break
	#---if composition is available we continue
	wordspace['new_composition'] = [[name,count*factor] for name,count in wordspace['composition']]
	kwargs = {}
	if 'buffer' in wordspace: kwargs['flag'] = ' -dist %.2f %.2f %.2f'%tuple(wordspace['buffer'])
	gmx('genconf',structure='system-input',gro='system-multiply',
		nbox="%d %d %d"%(nx,ny,nz),log='genconf-multiply',**kwargs)
	#---copy ITP files
	for itp in wordspace.itp:
		filecopy(wordspace.last_step+itp,wordspace.step+itp)
	#---reorder the GRO for convenience
	with open(wordspace['step']+'system-multiply.gro') as fp: lines = fp.readlines()
	#---collect all unique resiue/atom combinations
	combos = list(set([l[5:15] for l in lines]))

	#---for each element in the composition, extract all of the residues for that element
	lines_reorder = []
	lines_reorder.extend(lines[:2])
	#---develop a list of filtering rules
	keylist = {}
	for key,count in wordspace['new_composition']:
		if key in [wordspace[i] for i in ['anion','cation']]:
			keylist[key] = 'regex',(('ION',key),slice(5,15),'\s*%s\s*%s\s*')
		elif re.match('^(p|P)rotein',key) and key+'.itp' in wordspace.itp:
			#---custom procedure for finding proteins which have variegated residue numbers
			itp = read_itp(wordspace.step+key+'.itp')
			residues_starts = []
			seq = list(zip(*itp['atoms'])[3])
			residues = [i[5:10].strip() for i in lines]
			for i in range(len(residues)-len(seq)):
				#---minor speed up by checking the first one
				if seq[0]==residues[i] and residues[i:i+len(seq)]==seq: 
					residues_starts.append(i)
			keylist[key] = 'slices',[slice(i,i+len(seq)) for i in residues_starts]
		else: keylist[key] = 'regex',(key,slice(5,10),'\s*%s\s*')
	for key,count in wordspace['new_composition']:
		method,details = keylist[key]
		if method == 'regex':
			key,sl,regex = details
			lines_reorder.extend([l for l in lines[2:-1] if re.match(regex%key,l[sl])])	
		elif method == 'slices':
			for sl in details: lines_reorder.extend(lines[sl])	
		else: raise
	lines_reorder.extend([lines[-1]])
	with open(wordspace['step']+'system-multiply-reorder.gro','w') as fp: 
		for line in lines_reorder: fp.write(line)

	filecopy(wordspace['step']+'system-multiply-reorder.gro',wordspace['step']+'system.gro')
	wordspace['composition'] = tuple(wordspace['new_composition'])
	del wordspace['new_composition']
Ejemplo n.º 27
0
def solvate(structure, top):
    """
	solvate(structure,top)
	Standard solvate procedure for atomistic protein in water.
	"""

    #---purge the wordspace of solvent and anions in case we are resuming
    for key in [wordspace['anion'], wordspace['cation'], 'SOL']:
        if key in zip(*wordspace['composition'])[0]:
            del wordspace['composition'][zip(
                *wordspace['composition'])[0].index(key)]
    gmx('editconf',
        structure=structure,
        gro='solvate-box-alone',
        log='editconf-checksize',
        flag='-d 0')
    with open(wordspace['step'] + 'log-editconf-checksize', 'r') as fp:
        lines = fp.readlines()
    boxdims = map(
        lambda y: float(y),
        re.findall(
            '\s*box vectors \:\s*([^\s]+)\s+([^\s]+)\s+([^\s]+)',
            filter(lambda x: re.match('\s*box vectors', x),
                   lines).pop()).pop())
    boxvecs = tuple([i + 2 * wordspace['water_buffer'] for i in boxdims])
    center = tuple([i / 2. for i in boxvecs])
    #---cube is not implemented yet
    gmx('editconf',
        structure=structure,
        gro='solvate-protein',
        flags='-center %f %f %f' % center + ' ' + '-box %f %f %f' % boxvecs,
        log='editconf-center-protein')
    gmx(
        'genbox',
        structure='solvate-protein',
        solvent=wordspace['solvent'],
        gro='solvate-dense',  #top='solvate-standard',
        log='genbox-solvate')
    #---trim waters if the protein_water_gap setting is not False
    if 'protein_water_gap' in wordspace and wordspace[
            'protein_water_gap'] != False:
        trim_waters(structure='solvate-dense',
                    gro='solvate',
                    gap=wordspace['protein_water_gap'],
                    boxvecs=boxvecs)
    else:
        filecopy(wordspace['step'] + 'solvate-dense.gro',
                 wordspace['step'] + 'solvate.gro')
    gmx('make_ndx',
        structure='solvate',
        ndx='solvate-water-check',
        inpipe='q\n',
        log='make-ndx-solvate-check')
    with open(wordspace['step'] + 'log-make-ndx-solvate-check', 'r') as fp:
        lines = fp.readlines()
    nwaters = int(
        re.findall(
            '\s*[0-9]+\s+Water\s+:\s+([0-9]+)\s+atoms',
            filter(lambda x: re.match('\s*[0-9]+\s+Water', x),
                   lines).pop()).pop()) / 3
    wordspace['water_without_ions'] = nwaters
    component('SOL', count=nwaters)
    #---add the suffix so that water is referred to by its name in the settings
    include(wordspace['water'], ff=True)
    write_top('solvate.top')
Ejemplo n.º 28
0
def solvate_bilayer(structure='vacuum'):
    """
	Solvate a CGMD bilayer (possibly with proteins) avoiding overlaps.
	"""

    #---check the size of the slab
    incoming_structure = str(structure)
    boxdims_old, boxdims = get_box_vectors(structure)
    #---check the size of the water box
    waterbox = wordspace.water_box
    basedim, _ = get_box_vectors(waterbox)
    if not all([i == basedim[0] for i in basedim]):
        raise Exception('[ERROR] expecting water box "" to be cubic')
    else:
        basedim = basedim[0]
    #---make an oversized water box
    newdims = boxdims_old[:2] + [wordspace['solvent_thickness']]
    gmx('genconf',
        structure=waterbox,
        gro='solvate-empty-uncentered-untrimmed',
        nbox=' '.join([str(int(i / basedim + 1)) for i in newdims]),
        log='genconf')
    #---trim the blank water box
    trim_waters(structure='solvate-empty-uncentered-untrimmed',
                gro='solvate-empty-uncentered',
                boxcut=True,
                boxvecs=newdims,
                gap=0.0,
                method=wordspace.atom_resolution)
    #---update waters
    structure = 'solvate-empty-uncentered'
    component(wordspace.sol, count=count_molecules(structure, wordspace.sol))
    #---translate the water box
    gmx('editconf',
        structure=structure,
        gro='solvate-water-shifted',
        flag='-translate 0 0 %f' %
        (wordspace['bilayer_dimensions_slab'][2] / 2.),
        log='editconf-solvate-shift')
    #---combine and trim with new box vectors
    structure = 'solvate-water-shifted'
    boxdims_old, boxdims = get_box_vectors(structure)
    boxvecs = wordspace['bilayer_dimensions_slab'][:2] + [
        wordspace['bilayer_dimensions_slab'][2] + boxdims[2]
    ]
    gro_combinator('%s.gro' % incoming_structure,
                   structure,
                   box=boxvecs,
                   cwd=wordspace['step'],
                   gro='solvate-dense')
    structure = 'solvate-dense'
    #---trim everything so that waters are positioned in the box without steric clashes
    trim_waters(structure=structure,
                gro='solvate',
                boxcut=False,
                gap=wordspace['protein_water_gap'],
                method=wordspace.atom_resolution,
                boxvecs=boxvecs)
    structure = 'solvate'
    nwaters = count_molecules(structure, wordspace.sol) / ({
        'aamd': 3.0,
        'cgmd': 1.0
    }[wordspace.atom_resolution])
    if round(nwaters) != nwaters:
        raise Exception('[ERROR] fractional water molecules')
    else:
        nwaters = int(nwaters)
    component(wordspace.sol, count=nwaters)
    wordspace['bilayer_dimensions_solvate'] = boxvecs
    wordspace['water_without_ions'] = nwaters
Ejemplo n.º 29
0
def multiply(nx=1, ny=1, nz=1, quirky_ions=True):
    """
	Make a copy of a simulation box in multiple directions.
	"""

    factor = nx * ny * nz
    #---update the composition
    #---if the last step doesn't have the composition we step backwards and pick up requirements
    #---note that "protein_ready" is important for the bilayer_sorter
    for prereq in [
            'composition', 'lipids', 'cation', 'anion', 'protein_ready'
    ]:
        if prereq not in wordspace:
            steplist = detect_last(steplist=True)[::-1]
            #---walk backwards through steps until we find the commposition
            for ii, i in enumerate(steplist):
                oldspace = resume(read_only=True,
                                  step=int(re.match('s([0-9]+)-', i).group(1)))
                if prereq in oldspace:
                    wordspace[prereq] = deepcopy(oldspace[prereq])
                    break
    #---if composition is available we continue
    wordspace['new_composition'] = [[name, count * factor]
                                    for name, count in wordspace['composition']
                                    ]
    kwargs = {}
    if 'buffer' in wordspace:
        kwargs['flag'] = ' -dist %.2f %.2f %.2f' % tuple(wordspace['buffer'])
    gmx('genconf',
        structure='system-input',
        gro='system-multiply',
        nbox="%d %d %d" % (nx, ny, nz),
        log='genconf-multiply',
        **kwargs)
    #---copy ITP files
    for itp in wordspace.itp:
        filecopy(wordspace.last_step + itp, wordspace.step + itp)
    #---reorder the GRO for convenience
    with open(wordspace['step'] + 'system-multiply.gro') as fp:
        lines = fp.readlines()
    #---collect all unique resiue/atom combinations
    combos = list(set([l[5:15] for l in lines]))

    #---for each element in the composition, extract all of the residues for that element
    lines_reorder = []
    lines_reorder.extend(lines[:2])
    #---develop a list of filtering rules
    keylist = {}
    for key, count in wordspace['new_composition']:
        if key in [wordspace[i] for i in ['anion', 'cation']]:
            keylist[key] = 'regex', (('ION', key), slice(5,
                                                         15), '\s*%s\s*%s\s*')
        elif re.match('^(p|P)rotein', key) and key + '.itp' in wordspace.itp:
            #---custom procedure for finding proteins which have variegated residue numbers
            itp = read_itp(wordspace.step + key + '.itp')
            residues_starts = []
            seq = list(zip(*itp['atoms'])[3])
            residues = [i[5:10].strip() for i in lines]
            for i in range(len(residues) - len(seq)):
                #---minor speed up by checking the first one
                if seq[0] == residues[i] and residues[i:i + len(seq)] == seq:
                    residues_starts.append(i)
            keylist[key] = 'slices', [
                slice(i, i + len(seq)) for i in residues_starts
            ]
        else:
            keylist[key] = 'regex', (key, slice(5, 10), '\s*%s\s*')
    for key, count in wordspace['new_composition']:
        method, details = keylist[key]
        if method == 'regex':
            key, sl, regex = details
            lines_reorder.extend(
                [l for l in lines[2:-1] if re.match(regex % key, l[sl])])
        elif method == 'slices':
            for sl in details:
                lines_reorder.extend(lines[sl])
        else:
            raise
    lines_reorder.extend([lines[-1]])
    with open(wordspace['step'] + 'system-multiply-reorder.gro', 'w') as fp:
        for line in lines_reorder:
            fp.write(line)

    filecopy(wordspace['step'] + 'system-multiply-reorder.gro',
             wordspace['step'] + 'system.gro')
    wordspace['composition'] = tuple(wordspace['new_composition'])
    del wordspace['new_composition']
Ejemplo n.º 30
0
def solvate_bilayer(structure='vacuum'):
    """
	Solvate a CGMD bilayer (possibly with proteins) avoiding overlaps.
	"""

    #---check the size of the slab
    incoming_structure = str(structure)
    boxdims_old, boxdims = get_box_vectors(structure)

    #---! standardize these?
    basedim = 3.64428
    waterbox = 'inputs/martini-water'

    #---make an oversized water box
    newdims = boxdims_old[:2] + [wordspace['solvent_thickness']]
    #import pdb;pdb.set_trace()
    gmx('genconf',
        structure='martini-water',
        gro='solvate-empty-uncentered-untrimmed',
        nbox=' '.join([str(int(i / basedim + 1)) for i in newdims]),
        log='genconf')

    #---trimming waters
    with open(wordspace['step'] + 'solvate-empty-uncentered-untrimmed.gro',
              'r') as fp:
        lines = fp.readlines()
    modlines = []
    for line in lines[2:-1]:
        coords = [float(i) for i in line[20:].split()][:3]
        if all([coords[i] < newdims[i] for i in range(3)]):
            modlines.append(line)
    with open(wordspace['step'] + 'solvate-empty-uncentered.gro', 'w') as fp:
        fp.write(lines[0])
        fp.write(str(len(modlines)) + '\n')
        for l in modlines:
            fp.write(l)
        fp.write(lines[-1])

    #---update waters
    structure = 'solvate-empty-uncentered'
    component('W', count=count_molecules(structure, 'W'))
    #---translate the water box
    gmx('editconf',
        structure=structure,
        gro='solvate-water-shifted',
        flag='-translate 0 0 %f' %
        (wordspace['bilayer_dimensions_slab'][2] / 2.),
        log='editconf-solvate-shift')

    #---combine and trim with new box vectors
    #---! skipping minimization?
    structure = 'solvate-water-shifted'
    boxdims_old, boxdims = get_box_vectors(structure)
    boxvecs = wordspace['bilayer_dimensions_slab'][:2] + [
        wordspace['bilayer_dimensions_slab'][2] + boxdims[2]
    ]
    gro_combinator('%s.gro' % incoming_structure,
                   structure,
                   box=boxvecs,
                   cwd=wordspace['step'],
                   gro='solvate-dense')
    structure = 'solvate-dense'
    trim_waters(structure=structure,
                gro='solvate',
                boxcut=False,
                gap=wordspace['protein_water_gap'],
                method='cgmd',
                boxvecs=boxvecs)
    structure = 'solvate'
    nwaters = count_molecules(structure, 'W')
    component('W', count=nwaters)
    wordspace['bilayer_dimensions_solvate'] = boxvecs
    wordspace['water_without_ions'] = nwaters