def setupHydrationCalculation(molecule): """ """ # get current directory current_path = os.getcwd() # Center the molecule. OECenter(molecule) # get molecule name molecule_name = molecule.GetTitle() print molecule_name # create molecule path/directory molecule_path = os.path.abspath(os.path.join('molecules', molecule_name)) os.makedirs(molecule_path) # Write mol2 file for the molecule. writeMolecule(molecule, os.path.join(molecule_path, 'solute.mol2')) # Write GAFF parameters for gromacs, using antechamber to generate AM1-BCC charges. parameterizeForGromacs(molecule, topology_filename = os.path.join(molecule_path,'solute.top'), coordinate_filename = os.path.join(molecule_path,'solute.gro'), charge_model = 'bcc', resname = 'MOL') # Modify gromacs topology file for alchemical free energy calculation. perturbGromacsTopology(os.path.join(molecule_path,'solute.top'), molecule) # Convert gromacs topology to an .itp file suitable for inclusion. top_to_itp(os.path.join(molecule_path,'solute.top'), os.path.join(molecule_path,'solute.itp'), moleculetype = molecule_name) # SET UP VACUUM SIMULATION # construct pathname for vacuum simulations vacuum_path = os.path.join(molecule_path, 'vacuum') os.mkdir(vacuum_path) os.chdir(vacuum_path) # create molecule in enlarged box command = 'editconf_d -f ../solute.gro -o system.gro -bt cubic -d 50.0 -center 0.0 0.0 0.0' print command output = commands.getoutput(command) print output # create topology file topology_contents = """ ; amber forcefield #include "ffamber03.itp" ; my molecule #include "../solute.itp" [ system ] %(molecule_name)s in vacuum [ molecules ] ; Compound nmols %(molecule_name)s 1 """ % vars() writeFile('system.top', topology_contents) # construct .mdp files mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-vacuum', 'output'])) mdpfile.write(os.path.join(vacuum_path, 'minimization-unconstrained.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-vacuum', 'constraints', 'output'])) mdpfile.write(os.path.join(vacuum_path, 'minimization-constrained.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-vacuum', 'constraints', 'thermostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(vacuum_path, 'production.mdp')) # write shell script for minimization and production contents = """\ #/bin/tcsh source /Users/jchodera/local/gromacs-3.1.4-fe/i386-apple-darwin8.11.1/bin/GMXRC.csh setenv GROMPP grompp_d setenv MDRUN mdrun_d # unconstrained minimization $GROMPP -f minimization-unconstrained.mdp -c system.gro -p system.top -o minimization-unconstrained.tpr -maxwarn 10000 $MDRUN -s minimization-unconstrained.tpr -x minimization-unconstrained.xtc -c minimized-unconstrained.gro -e minimization-unconstrained.edr -g minimization-unconstrained.log # constrained minimization $GROMPP -f minimization-constrained.mdp -c minimized-unconstrained.gro -p system.top -o minimization-constrained.tpr -maxwarn 10000 $MDRUN -s minimization-constrained.tpr -x minimization-constrained.xtc -c minimized-constrained.gro -e minimization-constrained.edr -g minimization-constrained.log # production $GROMPP -f production.mdp -c minimized-constrained.gro -p system.top -o production.tpr -maxwarn 10000 $MDRUN -v -s production.tpr -o production.trr -x production.xtc -c production.gro -e production.edr -g production.log echo 0 | trjconv_d -f production.xtc -o production.pdb -s production.tpr """ % vars() writeFile(os.path.join(vacuum_path, 'run.sh'), contents) # SET UP SOLVATED CALCULATION # construct pathname for solvent simulations solvated_path = os.path.join(molecule_path, 'solvent') os.mkdir(solvated_path) os.chdir(solvated_path) # write enlarged box for solvent command = 'editconf_d -f ../solute.gro -o solute.gro -bt octahedron -d 1.0 -center 0.0 0.0 0.0' print command output = commands.getoutput(command) print output # write topology topology_contents = """ ; amber forcefield #include "ffamber03.itp" ; my molecule #include "../solute.itp" ; TIP3P water #include "ffamber_tip3p.itp" [ system ] %(molecule_name)s in solvent [ molecules ] ; Compound nmols %(molecule_name)s 1 """ % vars() writeFile('system.top', topology_contents) # solvate command = 'genbox_d -cp solute.gro -cs ffamber_tip3p.gro -o system.gro -p system.top' # command = 'genbox_d -cp solute.gro -cs tip3p-pme-waterbox.gro -o system.gro -p system.top' # use our special tip3p box # command = 'genbox_d -cp solute.gro -cs tip3p-pme-waterbox.gro -o system.gro -p system.top -vdwd 0.0' # insert waters but don't cull overlap print command output = commands.getoutput(command) print output # construct .mdp files mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'output'])) mdpfile.write(os.path.join(solvated_path, 'minimization-unconstrained.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'constraints', 'output'])) mdpfile.write(os.path.join(solvated_path, 'minimization-constrained.mdp')) # mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat-equilibration', 'barostat', 'output'])) # mdpfile.randomizeSeed() # randomize velocities # mdpfile.setParameter('nsteps', '25000') # 10 ps equilibration # mdpfile.write(os.path.join(solvated_path, 'equilibration.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(solvated_path, 'production.mdp')) # write run script contents = """\ #/bin/tcsh source /Users/jchodera/local/gromacs-3.1.4-fe/i386-apple-darwin8.11.1/bin/GMXRC.csh setenv GROMPP grompp_d setenv MDRUN mdrun_d # unconstrained minimization $GROMPP -f minimization-unconstrained.mdp -c system.gro -p system.top -o minimization-unconstrained.tpr -maxwarn 10000 $MDRUN -s minimization-unconstrained.tpr -x minimization-unconstrained.xtc -c minimized-unconstrained.gro -e minimization-unconstrained.edr -g minimization-unconstrained.log # constrained minimization $GROMPP -f minimization-constrained.mdp -c minimized-unconstrained.gro -p system.top -o minimization-constrained.tpr -maxwarn 10000 $MDRUN -s minimization-constrained.tpr -x minimization-constrained.xtc -c minimized-constrained.gro -e minimization-constrained.edr -g minimization-constrained.log # equilibration #$GROMPP -f equilibration.mdp -c minimized-constrained.gro -p system.top -o equilibration.tpr -maxwarn 10000 #$MDRUN -v -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.gro -e equilibration.edr -g equilibration.log #echo 0 | trjconv_d -f equilibration.xtc -o equilibration.pdb -s equilibration.tpr # production $GROMPP -f production.mdp -c minimized-constrained.gro -p system.top -o production.tpr -maxwarn 10000 #$GROMPP -f production.mdp -c equilibration.gro -p system.top -o production.tpr -maxwarn 10000 #$GROMPP -f production.mdp -c system.gro -p system.top -o production.tpr -maxwarn 10000 $MDRUN -v -s production.tpr -o production.trr -x production.xtc -c production.gro -e production.edr -g production.log echo 0 | trjconv_d -f production.xtc -o production.pdb -s production.tpr """ % vars() writeFile(os.path.join(solvated_path, 'run.sh'), contents) # restore working directory os.chdir(current_path) return
def setupHydrationCalculation(solute, nreplicates=1, verbose=True, jobname="hydration"): """Set up an absolute alchemical hydration free energy calculation for the given molecule. ARGUMENTS solute (OEMol) - the molecule for which hydration free energy is to be computed (with fully explicit hydrogens) in the desired protonation state. OPTIONAL ARGUMENTS nreplicates (integer) - the number of replicates to set up (default: 1) verbose (boolean) - if True, extra debug information will be printed (default: True) jobname (string) - string to use for job name (default: "hydration") NOTES A directory will be created 'molecules/[molecule name]' as obtained from molecule.GetTitle(). """ # get current directory current_path = os.getcwd() # Center the solute molecule. OECenter(solute) # get molecule name solute_name = molecule.GetTitle() if verbose: print solute_name # create molecule path/directory work_path = os.path.abspath(os.path.join('molecules', solute_name)) os.makedirs(work_path) # # Write mol2 file for the molecule. # writeMolecule(solute, os.path.join(solute_path, 'solute.mol2')) # # Write GAFF parameters for gromacs, using antechamber to generate AM1-BCC charges. # parameterizeForGromacs(molecule, topology_filename = os.path.join(molecule_path,'solute.top'), coordinate_filename = os.path.join(molecule_path,'solute.gro'), charge_model = 'bcc', resname = 'MOL') # # Modify gromacs topology file for alchemical free energy calculation. # perturbGromacsTopology(os.path.join(molecule_path,'solute.top'), molecule) # # Convert gromacs topology to an .itp file suitable for inclusion. # top_to_itp(os.path.join(molecule_path,'solute.top'), os.path.join(molecule_path,'solute.itp'), moleculetype = molecule_name) # get pathnames mdrun = globals()['mdrun'] grompp = globals()['grompp'] editconf = globals()['editconf'] # SET UP SOLUTE TOPOLOGY if verbose: print "\nCONSTRUCTING SOLUTE TOPOLOGY" # Get formal charge of ligand. solute_charge = formalCharge(solute) if verbose: print "solute formal charge is %d" % solute_charge # Write molecule with explicit hydrogens to mol2 file. print "Writing solute mol2 file..." solute_mol2_filename = os.path.abspath( os.path.join(work_path, 'solute.mol2')) writeMolecule(solute, solute_mol2_filename) # Set substructure name (which will become residue name). print "Modifying molecule name..." modifySubstructureName(solute_mol2_filename, 'MOL') # Run antechamber to assign GAFF atom types. print "Running antechamber..." os.chdir(work_path) gaff_mol2_filename = os.path.join(work_path, 'solute.gaff.mol2') charge_model = 'bcc' command = 'antechamber -i %(solute_mol2_filename)s -fi mol2 -o solute.gaff.mol2 -fo mol2 -c %(charge_model)s -nc %(solute_charge)d > antechamber.out' % vars( ) if verbose: print command output = commands.getoutput(command) if verbose: print output os.chdir(current_path) # Generate frcmod file for additional GAFF parameters. solute_frcmod_filename = os.path.join(work_path, 'frcmod.solute') command = 'parmchk -i %(gaff_mol2_filename)s -f mol2 -o %(solute_frcmod_filename)s' % vars( ) if verbose: print command output = commands.getoutput(command) if verbose: print output # Run LEaP to generate topology / coordinates. solute_prmtop_filename = os.path.join(work_path, 'solute.prmtop') solute_crd_filename = os.path.join(work_path, 'solute.crd') solute_off_filename = os.path.join(work_path, 'solute.off') tleap_input_filename = os.path.join(work_path, 'setup-solute.leap.in') tleap_output_filename = os.path.join(work_path, 'setup-solute.leap.out') contents = """ # Load GAFF parameters. source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(solute_frcmod_filename)s # load solute solute = loadMol2 %(gaff_mol2_filename)s # check the solute check solute # report net charge charge solute # save AMBER parameters saveAmberParm solute %(solute_prmtop_filename)s %(solute_crd_filename)s # write .off file saveOff solute %(solute_off_filename)s # exit quit """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # extract total charge solute_charge = commands.getoutput( 'grep "Total unperturbed charge" %(tleap_output_filename)s | cut -c 27-' % vars()) solute_charge = int(round( float(solute_charge))) # round to nearest whole charge if verbose: print "solute charge is %d" % solute_charge # PREPARE SOLVATED SOLUTE print "\nPREPARING SOLVATED SOLUTE" # create the directory if it doesn't exist solvent_path = os.path.join(work_path, 'solvent') if not os.path.exists(solvent_path): os.makedirs(solvent_path) # solvate the solute print "Solvating the solute with tleap..." system_prmtop_filename = os.path.join(solvent_path, 'system.prmtop') system_crd_filename = os.path.join(solvent_path, 'system.crd') tleap_input_filename = os.path.join(solvent_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(solvent_path, 'setup-system.leap.out') clearance = globals()['clearance'] # clearance around solute (in A) contents = """ source leaprc.ff99 source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(solute_frcmod_filename)s # Load solute. loadOff %(solute_off_filename)s # Create system. system = combine { solute } """ % vars() # add counterions if (solute_charge != 0): nions = abs(solute_charge) if solute_charge < 0: iontype = 'Na+' if solute_charge > 0: iontype = 'Cl-' contents += """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Solvate in truncated octahedral box. solvateBox system TIP3PBOX %(clearance)f iso # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(solvent_path, 'system') os.chdir(solvent_path) command = '%(amb2gmx)s --prmtop system.prmtop --crd system.crd --outname system' % vars( ) print command output = commands.getoutput(command) print output os.chdir(current_path) # Extract box size. g96_filename = os.path.join(solvent_path, 'system.g96') g96_file = open(g96_filename, 'r') g96_lines = g96_file.readlines() g96_file.close() box_size = zeros([3], float32) for line_number in range(len(g96_lines)): if g96_lines[line_number][0:3] == 'BOX': # parse line with box size in nm line = g96_lines[line_number + 1] elements = line.split() box_size[0] = float(elements[0]) * 10.0 box_size[1] = float(elements[1]) * 10.0 box_size[2] = float(elements[2]) * 10.0 print "box_size = " print box_size # make a PDB file for checking print "Converting system to PDB..." os.chdir(solvent_path) command = 'cat system.crd | ambpdb -p system.prmtop > system.pdb' % vars() output = commands.getoutput(command) print output os.chdir(current_path) # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(solvent_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # add those atoms in the solute to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) perturbGromacsTopology(system_top_filename, solute, perturb_torsions=True, perturb_vdw=True, perturb_charges=True, perturb_atom_indices=perturb_atom_indices) # set up replicates for replicate in range(nreplicates): # Create replicate directory. working_path = os.path.join(solvent_path, '%d' % replicate) os.makedirs(working_path) # TODO: Modify solute coordinates in system.g96 to cycle through available conformations. # set up mdp files print "Writing mdp files for replicate %d..." % replicate mdpfile = MdpFile( compose_blocks([ 'header', 'minimization', 'nonbonded-solvent', 'constraints', 'output' ])) mdpfile.write(os.path.join(working_path, 'minimize.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'output' ])) mdpfile.setParameter('nsteps', '10000') # 20 ps equilibration mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(working_path, 'equilibration.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'free-energy', 'output' ])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(working_path, 'production.mdp')) # write run script print "Writing run script..." solvent_path = os.path.abspath(solvent_path) contents = """\ set#!/bin/tcsh #BSUB -J %(jobname)s_solvent #BSUB -o %(working_path)s/outfile.%%J #BSUB -e %(working_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source $GMXRC cd %(working_path)s # constrained minimize %(grompp)s -f minimize.mdp -c ../system.g96 -p ../system.top -o minimize.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # equilibration %(grompp)s -f equilibration.mdp -c minimize.g96 -p ../system.top -o equilibration.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.g96 -e equilibration.edr -g equilibration.log # production %(grompp)s -f production.mdp -c equilibration.g96 -p ../system.top -o production.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(working_path, 'run.sh'), contents) # SET UP VACUUM SIMULATION # construct pathname for vacuum simulations vacuum_path = os.path.join(work_path, 'vacuum') if not os.path.exists(vacuum_path): os.makedirs(vacuum_path) # solvate the solute print "Preparing vacuum solute with tleap..." system_prmtop_filename = os.path.join(vacuum_path, 'system.prmtop') system_crd_filename = os.path.join(vacuum_path, 'system.crd') tleap_input_filename = os.path.join(vacuum_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(vacuum_path, 'setup-system.leap.out') clearance = 50.0 # clearance in A contents = """ source leaprc.ff99 source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(solute_frcmod_filename)s # Load solute. loadOff %(solute_off_filename)s # Create system. system = combine { solute } """ % vars() # add counterions if (solute_charge != 0): nions = abs(solute_charge) if solute_charge < 0: iontype = 'Na+' if solute_charge > 0: iontype = 'Cl-' contents += """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Create big box. setBox system centers %(clearance)f iso # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') os.chdir(vacuum_path) command = '%(amb2gmx)s --prmtop system.prmtop --crd system.crd --outname system' % vars( ) print command output = commands.getoutput(command) print output os.chdir(current_path) # make a PDB file for checking print "Converting system to PDB..." os.chdir(vacuum_path) command = 'cat system.crd | ambpdb -p system.prmtop > system.pdb' % vars() output = commands.getoutput(command) print output os.chdir(current_path) # write enlarged box for solvent because LEaP doesn't do it right. system_g96_filename = os.path.join(vacuum_path, 'system.g96') command = '%s -f %s -o %s -bt cubic -box %f %f %f -center 0.0 0.0 0.0' % ( editconf, system_g96_filename, system_g96_filename, box_size[0] / 10.0, box_size[1] / 10.0, box_size[2] / 10.0) print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(vacuum_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') nions = 0 for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # DEBUG # add those atoms in the solute to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) # add counterions to balance solute if ((atom['residue'] == 'Na+') or (atom['residue'] == 'Cl-')) and (nions < abs(solute_charge)): print "WARNING: Solute has net charge of %(solute_charge)d -- will perturb counterions too." % vars( ) perturb_atom_indices.append(atom['nr']) nions += 1 perturbGromacsTopology(system_top_filename, solute, perturb_torsions=True, perturb_vdw=True, perturb_charges=True, perturb_atom_indices=perturb_atom_indices) # construct replicates for replicate in range(nreplicates): # Create replicate path. working_path = os.path.join(vacuum_path, '%d' % replicate) os.makedirs(working_path) # TODO: Modify solute coordinates in system.g96 to cycle through available conformations. # construct .mdp files print "Writing mdp files for replicate %d..." % replicate mdpfile = MdpFile( compose_blocks([ 'header', 'minimization', 'nonbonded-vacuum', 'constraints', 'output' ])) cutoff = box_size.min() / 10.0 / 2.0 - 0.0001 # compute cutoff mdpfile.setParameter('rlist', '%f' % cutoff) mdpfile.setParameter('rvdw', '%f' % cutoff) mdpfile.setParameter('rcoulomb', '%f' % cutoff) mdpfile.write(os.path.join(working_path, 'minimize.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-vacuum', 'constraints', 'thermostat', 'free-energy', 'output' ])) mdpfile.randomizeSeed() # randomize velocities mdpfile.setParameter('rlist', '%f' % cutoff) mdpfile.setParameter('rvdw', '%f' % cutoff) mdpfile.setParameter('rcoulomb', '%f' % cutoff) mdpfile.write(os.path.join(working_path, 'production.mdp')) # write shell script for minimization and production contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_vacuum #BSUB -o %(working_path)s/outfile.%%J #BSUB -e %(working_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source $GMXRC cd %(working_path)s # constrained minimize %(grompp)s -f minimize.mdp -c ../system.g96 -p ../system.top -o minimize.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # production %(grompp)s -f production.mdp -c minimize.g96 -p ../system.top -o production.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(working_path, 'run.sh'), contents) return
def setup_system(protein_pdb_filename, ligand_filename, work_path, parameter_path, GMXRC, jobname): """Set up a system for alchemical free energy calculation in gromacs. ARGUMENTS protein_pdb_filename (string) - name of ffamber-named protein PDB file ligand_filename (string) - name of mol2 file describing ligand work_path (string) - name of directory to place files in """ # get current directory current_path = os.getcwd() # create the work directory if it doesn't exist if not os.path.exists(work_path): os.makedirs(work_path) mdrun = globals()['mdrun'] grompp = globals()['grompp'] # SET UP PROTEIN TOPOLOGY print "\nCONSTRUCTING PROTEIN TOPOLOGY" # convert protein PDB file to AMBER naming conventions, dropping atoms that AMBER won't recognize (like protons) print "Converting PDB naming to AMBER..." protein_amberpdb_filename = os.path.join(work_path, 'protein-ambernames.pdb') rename_pdb_for_amber(protein_pdb_filename, protein_amberpdb_filename) # run leap to set up protein and report on net charge print "Running LEaP to set up protein..." protein_prmtop_filename = os.path.join(work_path,'protein.prmtop') protein_crd_filename = os.path.join(work_path,'protein.crd') protein_off_filename = os.path.join(work_path, 'protein.off') tleap_input_filename = os.path.join(work_path, 'setup-protein.leap.in') tleap_output_filename = os.path.join(work_path, 'setup-protein.leap.out') contents = """ # Load AMBER ff99 parameters. source leaprc.ff99 # Load phosphoresidue parameters. loadoff %(parameter_path)s/T1P.off loadoff %(parameter_path)s/T2P.off loadoff %(parameter_path)s/Y1P.off loadoff %(parameter_path)s/Y2P.off loadamberparams %(parameter_path)s/frcmod_t1p loadamberparams %(parameter_path)s/frcmod_t2p loadamberparams %(parameter_path)s/frcmod_y1p loadamberparams %(parameter_path)s/frcmod_y2p # Load PDB file with AMBER naming conventions, stripped of hydrogens. protein = loadpdb %(protein_amberpdb_filename)s # check the system check protein # report net charge charge protein # write out parameters saveAmberParm protein %(protein_prmtop_filename)s %(protein_crd_filename)s # write as LEaP object saveOff protein %(protein_off_filename)s # exit quit """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars() output = commands.getoutput(command) # extract total charge protein_charge = commands.getoutput('grep "Total unperturbed charge" %(tleap_output_filename)s | cut -c 27-' % vars()) protein_charge = int(round(float(protein_charge))) # round to nearest whole charge print protein_charge # SET UP LIGAND TOPOLOGY print "\nCONSTRUCTING LIGAND TOPOLOGY" # Read the ligand into OEMol. print "Reading ligand..." ligand = readMolecule(ligand_filename, normalize = True) # Get formal charge of ligand. ligand_charge = formalCharge(ligand) print "formal charge is %d" % ligand_charge # TODO: Choose most appropriate protonation and tautomeric state. # Write molecule with explicit hydrogens to mol2 file. print "Writing ligand mol2 file..." ligand_mol2_filename = os.path.abspath(os.path.join(work_path, 'ligand.mol2')) writeMolecule(ligand, ligand_mol2_filename) # Set substructure name (which will become residue name). print "Modifying molecule name..." modifySubstructureName(ligand_mol2_filename, 'MOL') # Run antechamber to assign GAFF atom types. print "Running antechamber..." os.chdir(work_path) gaff_mol2_filename = os.path.join(work_path, 'ligand.gaff.mol2') charge_model = 'bcc' command = 'antechamber -i %(ligand_mol2_filename)s -fi mol2 -o ligand.gaff.mol2 -fo mol2 -c %(charge_model)s -nc %(ligand_charge)d > antechamber.out' % vars() print command output = commands.getoutput(command) os.chdir(current_path) # Generate frcmod file for additional GAFF parameters. ligand_frcmod_filename = os.path.join(work_path, 'frcmod.ligand') output = commands.getoutput('parmchk -i %(gaff_mol2_filename)s -f mol2 -o %(ligand_frcmod_filename)s' % vars()) print output # Run LEaP to generate topology / coordinates. ligand_prmtop_filename = os.path.join(work_path,'ligand.prmtop') ligand_crd_filename = os.path.join(work_path,'ligand.crd') ligand_off_filename = os.path.join(work_path, 'ligand.off') tleap_input_filename = os.path.join(work_path, 'setup-ligand.leap.in') tleap_output_filename = os.path.join(work_path, 'setup-ligand.leap.out') contents = """ # Load GAFF parameters. source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # load ligand ligand = loadMol2 %(gaff_mol2_filename)s # check the ligand check ligand # report net charge charge ligand # save AMBER parameters saveAmberParm ligand %(ligand_prmtop_filename)s %(ligand_crd_filename)s # write .off file saveOff ligand %(ligand_off_filename)s # exit quit """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars() output = commands.getoutput(command) # extract total charge ligand_charge = commands.getoutput('grep "Total unperturbed charge" %(tleap_output_filename)s | cut -c 27-' % vars()) ligand_charge = int(round(float(ligand_charge))) # round to nearest whole charge print "ligand charge is %d" % ligand_charge # SET UP VACUUM SIMULATION # construct pathname for vacuum simulations vacuum_path = os.path.join(work_path, 'vacuum') if not os.path.exists(vacuum_path): os.makedirs(vacuum_path) # solvate the ligand print "Preparing vacuum ligand with tleap..." system_prmtop_filename = os.path.join(vacuum_path,'system.prmtop') system_crd_filename = os.path.join(vacuum_path,'system.crd') tleap_input_filename = os.path.join(vacuum_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(vacuum_path, 'setup-system.leap.out') clearance = 50.0 # clearance in A contents = """ source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # Load ligand. loadOff %(ligand_off_filename)s # Create system. system = combine { ligand } """ % vars() # add counterions if (ligand_charge != 0): nions = abs(ligand_charge) if ligand_charge < 0: iontype = 'Na+' if ligand_charge > 0: iontype = 'Cl-' contents += """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Create big box. setBox system centers %(clearance)f # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars() output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(vacuum_path, 'system') command = '%(amb2gmx)s --prmtop %(system_prmtop_filename)s --crd %(system_crd_filename)s --outname %(system_prefix)s' % vars() print command output = commands.getoutput(command) print output # write enlarged box for solvent because LEaP doesn't do it right. system_g96_filename = os.path.join(vacuum_path, 'system.g96') command = '%s -f %s -o %s -bt octahedron -d %f -center 0.0 0.0 0.0' % (editconf, system_g96_filename, system_g96_filename, clearance) print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(vacuum_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') nions = 0 for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # add those atoms in the ligand to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) # add counterions to balance ligand if ((atom['residue'] == 'Na+') or (atom['residue'] == 'Cl-')) and (nions < abs(ligand_charge)): perturb_atom_indices.append(atom['nr']) nions += 1 perturbGromacsTopology(system_top_filename, ligand, perturb_torsions = True, perturb_vdw = True, perturb_charges = True, perturb_atom_indices = perturb_atom_indices) # construct .mdp files mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-vacuum', 'constraints', 'output'])) mdpfile.write(os.path.join(vacuum_path, 'minimize.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-vacuum', 'constraints', 'thermostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(vacuum_path, 'production.mdp')) vacuum_path = os.path.abspath(vacuum_path) # write shell script for minimization and production contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_vacuum #BSUB -o %(vacuum_path)s/outfile.%%J #BSUB -e %(vacuum_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source %(GMXRC)s cd %(vacuum_path)s setenv RANSEED 1234 # constrained minimize %(grompp)s -f minimize.mdp -c system.g96 -p system.top -o minimize.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # production %(grompp)s -f production.mdp -c minimize.g96 -p system.top -o production.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(vacuum_path, 'run.sh'), contents) # PREPARE SOLVATED LIGAND print "\nPREPARING SOLVATED LIGAND" # create the directory if it doesn't exist solvent_path = os.path.join(work_path, 'solvent') if not os.path.exists(solvent_path): os.makedirs(solvent_path) # solvate the ligand print "Solvating the ligand with tleap..." system_prmtop_filename = os.path.join(solvent_path,'system.prmtop') system_crd_filename = os.path.join(solvent_path,'system.crd') tleap_input_filename = os.path.join(solvent_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(solvent_path, 'setup-system.leap.out') clearance = 10.0 # clearance in A contents = """ source leaprc.ff99 source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # Load ligand. loadOff %(ligand_off_filename)s # Create system. system = combine { ligand } """ % vars() # add counterions if (ligand_charge != 0): nions = abs(ligand_charge) if ligand_charge < 0: iontype = 'Na+' if ligand_charge > 0: iontype = 'Cl-' contents += """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Solvate in truncated octahedral box. solvateOct system TIP3PBOX %(clearance)f # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars() output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(solvent_path, 'system') command = '%(amb2gmx)s --prmtop %(system_prmtop_filename)s --crd %(system_crd_filename)s --outname %(system_prefix)s' % vars() print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(solvent_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # add those atoms in the ligand to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) perturbGromacsTopology(system_top_filename, ligand, perturb_torsions = True, perturb_vdw = True, perturb_charges = True, perturb_atom_indices = perturb_atom_indices) # set up mdp files print "Writing mdp files..." mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'constraints', 'output'])) mdpfile.write(os.path.join(solvent_path, 'minimize.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'output'])) mdpfile.setParameter('nsteps', '10000') # 20 ps equilibration mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(solvent_path, 'equilibration.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(solvent_path, 'production.mdp')) # write run script print "Writing run script..." solvent_path = os.path.abspath(solvent_path) contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_solvent #BSUB -o %(solvent_path)s/outfile.%%J #BSUB -e %(solvent_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source %(GMXRC)s cd %(solvent_path)s setenv RANSEED 1234 # constrained minimize %(grompp)s -f minimize.mdp -c system.g96 -p system.top -o minimize.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # equilibration %(grompp)s -f equilibration.mdp -c minimize.g96 -p system.top -o equilibration.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.g96 -e equilibration.edr -g equilibration.log # production %(grompp)s -f production.mdp -c equilibration.g96 -p system.top -o production.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(solvent_path, 'run.sh'), contents) # PREPARE SOLVATED COMPLEX print "\nPREPARING SOLVATED COMPLEX" # create the directory if it doesn't exist complex_path = os.path.join(work_path, 'complex') if not os.path.exists(complex_path): os.makedirs(complex_path) # solvate the ligand print "Solvating the complex with tleap..." system_prmtop_filename = os.path.join(complex_path,'system.prmtop') system_crd_filename = os.path.join(complex_path,'system.crd') tleap_input_filename = os.path.join(complex_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(complex_path, 'setup-system.leap.out') clearance = 10.0 # clearance in A contents = """ source leaprc.ff99 source leaprc.gaff loadamberparams %(parameter_path)s/frcmod_t1p loadamberparams %(parameter_path)s/frcmod_t2p loadamberparams %(parameter_path)s/frcmod_y1p loadamberparams %(parameter_path)s/frcmod_y2p # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # Load protein. loadOff %(protein_off_filename)s # Load ligand. loadOff %(ligand_off_filename)s # Create system. system = combine { protein ligand } """ % vars() # add counterions for ligand if (ligand_charge != 0): nions = abs(ligand_charge) if ligand_charge < 0: iontype = 'Na+' if ligand_charge > 0: iontype = 'Cl-' contents += """ # Add counterions for ligand (will be annihilated with ligand). addions system %(iontype)s %(nions)d """ % vars() # # add counterions for protein if (protein_charge != 0): nions = abs(protein_charge) if protein_charge < 0: iontype = 'Na+' if protein_charge > 0: iontype = 'Cl-' contents += """ # Add counterions for protein. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Solvate in truncated octahedral box. solvateOct system TIP3PBOX %(clearance)f # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars() output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(complex_path, 'system') command = '%(amb2gmx)s --prmtop %(system_prmtop_filename)s --crd %(system_crd_filename)s --outname %(system_prefix)s' % vars() print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(complex_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') nions = 0 for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # add those atoms in the ligand to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) # add counterions to balance ligand if ((atom['residue'] == 'Na+') or (atom['residue'] == 'Cl-')) and (nions < abs(ligand_charge)): perturb_atom_indices.append(atom['nr']) nions += 1 perturbGromacsTopology(system_top_filename, ligand, perturb_torsions = True, perturb_vdw = True, perturb_charges = True, perturb_atom_indices = perturb_atom_indices) # set up mdp files print "Writing mdp files..." mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'constraints', 'restraints', 'output'])) mdpfile.write(os.path.join(complex_path, 'minimize.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'output'])) mdpfile.setParameter('nsteps', '10000') # 20 ps equilibration mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(complex_path, 'equilibration.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'restraints', 'thermostat', 'barostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(complex_path, 'production.mdp')) # Copy restraint scripts to run directory shutil.copy(compute_angles,complex_path) shutil.copy(restraint_topology,complex_path) # write run script print "Writing run script..." complex_path = os.path.abspath(complex_path) contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_complex #BSUB -o %(complex_path)s/outfile.%%J #BSUB -e %(complex_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source %(GMXRC)s cd %(complex_path)s setenv RANSEED 1234 # create a tpr file from which to create restraints %(grompp)s -f minimize.mdp -c system.g96 -p system.top -o minimize.tpr -maxwarn 10000 -n system.ndx # Integrate restraints into pre-minimization topfile python computeangles.py -f system.g96 -s minimize.tpr -d $RANSEED python restraint_topology.py -n system -p . # constrained minimize with restraints %(grompp)s -f minimize.mdp -c system_restr.g96 -p system_restr.top -o minimize.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # equilibration with restraints %(grompp)s -f equilibration.mdp -c minimize.g96 -p system.top -o equilibration.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.g96 -e equilibration.edr -g equilibration.log # create a TPR file, integrate restraints %(grompp)s -f production.mdp -c equilibration.g96 -p system_restr.top -o production.tpr -maxwarn 10000 -n system.ndx cp system_restr.top minimize.top python computeangles.py -f equilibration.g96 -s production.tpr -d $RANSEED python restraint_topology.py -n equilibration -p . # production with restraints %(grompp)s -f production.mdp -c equilibration_restr.g96 -p minimize_restr.top -o production.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(complex_path, 'run.sh'), contents) return
def setup_complex_simulation(complex_path, jobname, ligand, ligand_off_filename, ligand_frcmod_filename, protein_off_filename, protein_charge, common_substructure): """Set up free energy calculation for ligand in complex. ARGUMENTS complex_path (string) - the pathname where the simulation is to be set up (created if doesn't exist). jobname (string) - job name to be used to form batch queue job name ligand (OEMol) - the ligand ligand_off_filename (string) - leap library for ligand ligand_frcmod_filename (string) - additional ligand parameters common_substructure (OEMol) - """ print "\nPREPARING SOLVATED COMPLEX" # create path if it doesn't exist if not os.path.exists(complex_path): os.makedirs(complex_path) # get ligand formal charge ligand_charge = formalCharge(ligand) # set up the system in tLEaP print "Solvating the complex with tleap..." system_prmtop_filename = os.path.join(complex_path,'system.prmtop') system_crd_filename = os.path.join(complex_path,'system.crd') tleap_input_filename = os.path.join(complex_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(complex_path, 'setup-system.leap.out') clearance = 10.0 # clearance in A to add around protein contents = """ source leaprc.ff03 source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # Load protein. loadOff %(protein_off_filename)s # Load ligand. loadOff %(ligand_off_filename)s # Create system. system = combine { protein ligand } """ % vars() # add counterions for ligand if (ligand_charge != 0): nions = abs(ligand_charge) if ligand_charge < 0: iontype = 'Na+' if ligand_charge > 0: iontype = 'Cl-' contents += """ # Add counterions for ligand (will be annihilated with ligand). addions system %(iontype)s %(nions)d """ % vars() # # add counterions for protein if (protein_charge != 0): nions = abs(protein_charge) if protein_charge < 0: iontype = 'Na+' if protein_charge > 0: iontype = 'Cl-' contents += """ # Add counterions for protein. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Solvate in truncated octahedral box. # solvateOct system TIP3PBOX %(clearance)f # solvate in rectilinear box solvateBox system TIP3PBOX %(clearance)f # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars() output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(complex_path, 'system') current_path = os.getcwd() os.chdir(complex_path) #command = '%(amb2gmx)s --prmtop %(system_prmtop_filename)s --crd %(system_crd_filename)s --outname %(system_prefix)s' % vars() command = '%(amb2gmx)s --prmtop system.prmtop --crd system.crd --outname system' % vars() print command output = commands.getoutput(command) print output os.chdir(current_path) # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(complex_path, 'system.top') perturbGromacsTopologyToIntermediate(system_top_filename, 'MOL', ligand, common_substructure, perturb_torsions = True) # set up mdp files print "Writing mdp files..." mdpfile = MdpFile(compose_blocks(['header', 'minimizationMZ', 'nonbonded-solvent', 'constraints', 'restraints', 'output'])) mdpfile.write(os.path.join(complex_path, 'minimize.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'output'])) mdpfile.setParameter('nsteps', '10000') # 20 ps equilibration mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(complex_path, 'equilibration.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'restraints', 'thermostat', 'barostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(complex_path, 'production.mdp')) # Copy restraint scripts to run directory shutil.copy(os.path.join(script_basepath,'compute_angles.py'),complex_path) shutil.copy(os.path.join(script_basepath,'restraint_topology.py'),complex_path) # write batch queue script print "Writing batch queue script..." complex_path = os.path.abspath(complex_path) contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_complex #BSUB -n 1 #BSUB -M 2000000 source $GMXRC # create a tpr file from which to create restraints grompp -f minimize.mdp -c system.g96 -p system.top -o minimize.tpr -maxwarn 10000 -n system.ndx # Integrate restraints into pre-minimization topfile python compute_angles.py -f system.g96 -s minimize.tpr -d $RANSEED python restraint_topology.py -n system -p . # constrained minimize with restraints grompp -f minimize.mdp -c system_restr.g96 -p system_restr.top -o minimize.tpr -maxwarn 10000 -n system.ndx mdrun -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # create a tpr file from which to create restraints grompp -f equilibration.mdp -c minimize.g96 -p system_restr.top -o equilibration.tpr -maxwarn 10000 -n system.ndx # Integrate restraints into pre-equilibration topfile cp system_restr.top minimize.top #python compute_angles.py -f minimize.g96 -s equilibration.tpr -d $RANSEED python restraint_topology.py -n minimize -p . # equilibration with restraints grompp -f equilibration.mdp -c minimize_restr.g96 -p minimize_restr.top -o equilibration.tpr -maxwarn 10000 -n system.ndx mdrun -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.g96 -e equilibration.edr -g equilibration.log # create a TPR file, integrate restraints grompp -f production.mdp -c equilibration.g96 -p minimize_restr.top -o production.tpr -maxwarn 10000 -n system.ndx cp minimize_restr.top equilibration.top #python compute_angles.py -f equilibration.g96 -s production.tpr -d $RANSEED python restraint_topology.py -n equilibration -p . # production with restraints grompp -f production.mdp -c equilibration_restr.g96 -p equilibration_restr.top -o production.tpr -maxwarn 10000 -n system.ndx mdrun -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(complex_path, 'run.sh'), contents) return
def setup_system(protein_pdb_filename, ligand_filename, work_path, parameter_path, GMXRC, jobname): """Set up a system for alchemical free energy calculation in gromacs. ARGUMENTS protein_pdb_filename (string) - name of ffamber-named protein PDB file ligand_filename (string) - name of mol2 file describing ligand work_path (string) - name of directory to place files in """ # get current directory current_path = os.getcwd() # create the work directory if it doesn't exist if not os.path.exists(work_path): os.makedirs(work_path) mdrun = globals()['mdrun'] grompp = globals()['grompp'] # SET UP PROTEIN TOPOLOGY print "\nCONSTRUCTING PROTEIN TOPOLOGY" # convert protein PDB file to AMBER naming conventions, dropping atoms that AMBER won't recognize (like protons) print "Converting PDB naming to AMBER..." protein_amberpdb_filename = os.path.join(work_path, 'protein-ambernames.pdb') rename_pdb_for_amber(protein_pdb_filename, protein_amberpdb_filename) # run leap to set up protein and report on net charge print "Running LEaP to set up protein..." protein_prmtop_filename = os.path.join(work_path, 'protein.prmtop') protein_crd_filename = os.path.join(work_path, 'protein.crd') protein_off_filename = os.path.join(work_path, 'protein.off') tleap_input_filename = os.path.join(work_path, 'setup-protein.leap.in') tleap_output_filename = os.path.join(work_path, 'setup-protein.leap.out') contents = """ # Load AMBER ff99 parameters. source leaprc.ff99 # Load phosphoresidue parameters. loadoff %(parameter_path)s/T1P.off loadoff %(parameter_path)s/T2P.off loadoff %(parameter_path)s/Y1P.off loadoff %(parameter_path)s/Y2P.off loadamberparams %(parameter_path)s/frcmod_t1p loadamberparams %(parameter_path)s/frcmod_t2p loadamberparams %(parameter_path)s/frcmod_y1p loadamberparams %(parameter_path)s/frcmod_y2p # Load PDB file with AMBER naming conventions, stripped of hydrogens. protein = loadpdb %(protein_amberpdb_filename)s # check the system check protein # report net charge charge protein # write out parameters saveAmberParm protein %(protein_prmtop_filename)s %(protein_crd_filename)s # write as LEaP object saveOff protein %(protein_off_filename)s # exit quit """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # extract total charge protein_charge = commands.getoutput( 'grep "Total unperturbed charge" %(tleap_output_filename)s | cut -c 27-' % vars()) protein_charge = int(round( float(protein_charge))) # round to nearest whole charge print protein_charge # SET UP LIGAND TOPOLOGY print "\nCONSTRUCTING LIGAND TOPOLOGY" # Read the ligand into OEMol. print "Reading ligand..." ligand = readMolecule(ligand_filename, normalize=True) # Get formal charge of ligand. ligand_charge = formalCharge(ligand) print "formal charge is %d" % ligand_charge # TODO: Choose most appropriate protonation and tautomeric state. # Write molecule with explicit hydrogens to mol2 file. print "Writing ligand mol2 file..." ligand_mol2_filename = os.path.abspath( os.path.join(work_path, 'ligand.mol2')) writeMolecule(ligand, ligand_mol2_filename) # Set substructure name (which will become residue name). print "Modifying molecule name..." modifySubstructureName(ligand_mol2_filename, 'MOL') # Run antechamber to assign GAFF atom types. print "Running antechamber..." os.chdir(work_path) gaff_mol2_filename = os.path.join(work_path, 'ligand.gaff.mol2') charge_model = 'bcc' command = 'antechamber -i %(ligand_mol2_filename)s -fi mol2 -o ligand.gaff.mol2 -fo mol2 -c %(charge_model)s -nc %(ligand_charge)d > antechamber.out' % vars( ) print command output = commands.getoutput(command) os.chdir(current_path) # Generate frcmod file for additional GAFF parameters. ligand_frcmod_filename = os.path.join(work_path, 'frcmod.ligand') output = commands.getoutput( 'parmchk -i %(gaff_mol2_filename)s -f mol2 -o %(ligand_frcmod_filename)s' % vars()) print output # Run LEaP to generate topology / coordinates. ligand_prmtop_filename = os.path.join(work_path, 'ligand.prmtop') ligand_crd_filename = os.path.join(work_path, 'ligand.crd') ligand_off_filename = os.path.join(work_path, 'ligand.off') tleap_input_filename = os.path.join(work_path, 'setup-ligand.leap.in') tleap_output_filename = os.path.join(work_path, 'setup-ligand.leap.out') contents = """ # Load GAFF parameters. source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # load ligand ligand = loadMol2 %(gaff_mol2_filename)s # check the ligand check ligand # report net charge charge ligand # save AMBER parameters saveAmberParm ligand %(ligand_prmtop_filename)s %(ligand_crd_filename)s # write .off file saveOff ligand %(ligand_off_filename)s # exit quit """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # extract total charge ligand_charge = commands.getoutput( 'grep "Total unperturbed charge" %(tleap_output_filename)s | cut -c 27-' % vars()) ligand_charge = int(round( float(ligand_charge))) # round to nearest whole charge print "ligand charge is %d" % ligand_charge # SET UP VACUUM SIMULATION # construct pathname for vacuum simulations vacuum_path = os.path.join(work_path, 'vacuum') if not os.path.exists(vacuum_path): os.makedirs(vacuum_path) # solvate the ligand print "Preparing vacuum ligand with tleap..." system_prmtop_filename = os.path.join(vacuum_path, 'system.prmtop') system_crd_filename = os.path.join(vacuum_path, 'system.crd') tleap_input_filename = os.path.join(vacuum_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(vacuum_path, 'setup-system.leap.out') clearance = 50.0 # clearance in A contents = """ source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # Load ligand. loadOff %(ligand_off_filename)s # Create system. system = combine { ligand } """ % vars() # add counterions if (ligand_charge != 0): nions = abs(ligand_charge) if ligand_charge < 0: iontype = 'Na+' if ligand_charge > 0: iontype = 'Cl-' contents += """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Create big box. setBox system centers %(clearance)f # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(vacuum_path, 'system') command = '%(amb2gmx)s --prmtop %(system_prmtop_filename)s --crd %(system_crd_filename)s --outname %(system_prefix)s' % vars( ) print command output = commands.getoutput(command) print output # write enlarged box for solvent because LEaP doesn't do it right. system_g96_filename = os.path.join(vacuum_path, 'system.g96') command = '%s -f %s -o %s -bt octahedron -d %f -center 0.0 0.0 0.0' % ( editconf, system_g96_filename, system_g96_filename, clearance) print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(vacuum_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') nions = 0 for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # add those atoms in the ligand to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) # add counterions to balance ligand if ((atom['residue'] == 'Na+') or (atom['residue'] == 'Cl-')) and (nions < abs(ligand_charge)): perturb_atom_indices.append(atom['nr']) nions += 1 perturbGromacsTopology(system_top_filename, ligand, perturb_torsions=True, perturb_vdw=True, perturb_charges=True, perturb_atom_indices=perturb_atom_indices) # construct .mdp files mdpfile = MdpFile( compose_blocks([ 'header', 'minimization', 'nonbonded-vacuum', 'constraints', 'output' ])) mdpfile.write(os.path.join(vacuum_path, 'minimize.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-vacuum', 'constraints', 'thermostat', 'free-energy', 'output' ])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(vacuum_path, 'production.mdp')) vacuum_path = os.path.abspath(vacuum_path) # write shell script for minimization and production contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_vacuum #BSUB -o %(vacuum_path)s/outfile.%%J #BSUB -e %(vacuum_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source %(GMXRC)s cd %(vacuum_path)s setenv RANSEED 1234 # constrained minimize %(grompp)s -f minimize.mdp -c system.g96 -p system.top -o minimize.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # production %(grompp)s -f production.mdp -c minimize.g96 -p system.top -o production.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(vacuum_path, 'run.sh'), contents) # PREPARE SOLVATED LIGAND print "\nPREPARING SOLVATED LIGAND" # create the directory if it doesn't exist solvent_path = os.path.join(work_path, 'solvent') if not os.path.exists(solvent_path): os.makedirs(solvent_path) # solvate the ligand print "Solvating the ligand with tleap..." system_prmtop_filename = os.path.join(solvent_path, 'system.prmtop') system_crd_filename = os.path.join(solvent_path, 'system.crd') tleap_input_filename = os.path.join(solvent_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(solvent_path, 'setup-system.leap.out') clearance = 10.0 # clearance in A contents = """ source leaprc.ff99 source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # Load ligand. loadOff %(ligand_off_filename)s # Create system. system = combine { ligand } """ % vars() # add counterions if (ligand_charge != 0): nions = abs(ligand_charge) if ligand_charge < 0: iontype = 'Na+' if ligand_charge > 0: iontype = 'Cl-' contents += """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Solvate in truncated octahedral box. solvateOct system TIP3PBOX %(clearance)f # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(solvent_path, 'system') command = '%(amb2gmx)s --prmtop %(system_prmtop_filename)s --crd %(system_crd_filename)s --outname %(system_prefix)s' % vars( ) print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(solvent_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # add those atoms in the ligand to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) perturbGromacsTopology(system_top_filename, ligand, perturb_torsions=True, perturb_vdw=True, perturb_charges=True, perturb_atom_indices=perturb_atom_indices) # set up mdp files print "Writing mdp files..." mdpfile = MdpFile( compose_blocks([ 'header', 'minimization', 'nonbonded-solvent', 'constraints', 'output' ])) mdpfile.write(os.path.join(solvent_path, 'minimize.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'output' ])) mdpfile.setParameter('nsteps', '10000') # 20 ps equilibration mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(solvent_path, 'equilibration.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'free-energy', 'output' ])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(solvent_path, 'production.mdp')) # write run script print "Writing run script..." solvent_path = os.path.abspath(solvent_path) contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_solvent #BSUB -o %(solvent_path)s/outfile.%%J #BSUB -e %(solvent_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source %(GMXRC)s cd %(solvent_path)s setenv RANSEED 1234 # constrained minimize %(grompp)s -f minimize.mdp -c system.g96 -p system.top -o minimize.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # equilibration %(grompp)s -f equilibration.mdp -c minimize.g96 -p system.top -o equilibration.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.g96 -e equilibration.edr -g equilibration.log # production %(grompp)s -f production.mdp -c equilibration.g96 -p system.top -o production.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(solvent_path, 'run.sh'), contents) # PREPARE SOLVATED COMPLEX print "\nPREPARING SOLVATED COMPLEX" # create the directory if it doesn't exist complex_path = os.path.join(work_path, 'complex') if not os.path.exists(complex_path): os.makedirs(complex_path) # solvate the ligand print "Solvating the complex with tleap..." system_prmtop_filename = os.path.join(complex_path, 'system.prmtop') system_crd_filename = os.path.join(complex_path, 'system.crd') tleap_input_filename = os.path.join(complex_path, 'setup-system.leap.in') tleap_output_filename = os.path.join(complex_path, 'setup-system.leap.out') clearance = 10.0 # clearance in A contents = """ source leaprc.ff99 source leaprc.gaff loadamberparams %(parameter_path)s/frcmod_t1p loadamberparams %(parameter_path)s/frcmod_t2p loadamberparams %(parameter_path)s/frcmod_y1p loadamberparams %(parameter_path)s/frcmod_y2p # load antechamber-generated additional parameters mods = loadAmberParams %(ligand_frcmod_filename)s # Load protein. loadOff %(protein_off_filename)s # Load ligand. loadOff %(ligand_off_filename)s # Create system. system = combine { protein ligand } """ % vars() # add counterions for ligand if (ligand_charge != 0): nions = abs(ligand_charge) if ligand_charge < 0: iontype = 'Na+' if ligand_charge > 0: iontype = 'Cl-' contents += """ # Add counterions for ligand (will be annihilated with ligand). addions system %(iontype)s %(nions)d """ % vars() # # add counterions for protein if (protein_charge != 0): nions = abs(protein_charge) if protein_charge < 0: iontype = 'Na+' if protein_charge > 0: iontype = 'Cl-' contents += """ # Add counterions for protein. addions system %(iontype)s %(nions)d """ % vars() # contents += """ # Solvate in truncated octahedral box. solvateOct system TIP3PBOX %(clearance)f # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() write_file(tleap_input_filename, contents) command = 'tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s' % vars( ) output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv('MMTOOLSPATH'), 'converters', 'amb2gmx.pl') system_prefix = os.path.join(complex_path, 'system') command = '%(amb2gmx)s --prmtop %(system_prmtop_filename)s --crd %(system_crd_filename)s --outname %(system_prefix)s' % vars( ) print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(complex_path, 'system.top') lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, 'atoms') nions = 0 for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if (nelements < 8): continue # parse line atom = dict() atom['nr'] = int(elements[0]) atom['type'] = elements[1] atom['resnr'] = int(elements[2]) atom['residue'] = elements[3] atom['atom'] = elements[4] atom['cgnr'] = int(elements[5]) atom['charge'] = float(elements[6]) atom['mass'] = float(elements[7]) # add those atoms in the ligand to our list if atom['residue'] == 'MOL': perturb_atom_indices.append(atom['nr']) # add counterions to balance ligand if ((atom['residue'] == 'Na+') or (atom['residue'] == 'Cl-')) and (nions < abs(ligand_charge)): perturb_atom_indices.append(atom['nr']) nions += 1 perturbGromacsTopology(system_top_filename, ligand, perturb_torsions=True, perturb_vdw=True, perturb_charges=True, perturb_atom_indices=perturb_atom_indices) # set up mdp files print "Writing mdp files..." mdpfile = MdpFile( compose_blocks([ 'header', 'minimization', 'nonbonded-solvent', 'constraints', 'restraints', 'output' ])) mdpfile.write(os.path.join(complex_path, 'minimize.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'output' ])) mdpfile.setParameter('nsteps', '10000') # 20 ps equilibration mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(complex_path, 'equilibration.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-solvent', 'constraints', 'restraints', 'thermostat', 'barostat', 'free-energy', 'output' ])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(complex_path, 'production.mdp')) # Copy restraint scripts to run directory shutil.copy(compute_angles, complex_path) shutil.copy(restraint_topology, complex_path) # write run script print "Writing run script..." complex_path = os.path.abspath(complex_path) contents = """\ #!/bin/tcsh #BSUB -J %(jobname)s_complex #BSUB -o %(complex_path)s/outfile.%%J #BSUB -e %(complex_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source %(GMXRC)s cd %(complex_path)s setenv RANSEED 1234 # create a tpr file from which to create restraints %(grompp)s -f minimize.mdp -c system.g96 -p system.top -o minimize.tpr -maxwarn 10000 -n system.ndx # Integrate restraints into pre-minimization topfile python computeangles.py -f system.g96 -s minimize.tpr -d $RANSEED python restraint_topology.py -n system -p . # constrained minimize with restraints %(grompp)s -f minimize.mdp -c system_restr.g96 -p system_restr.top -o minimize.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # equilibration with restraints %(grompp)s -f equilibration.mdp -c minimize.g96 -p system.top -o equilibration.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.g96 -e equilibration.edr -g equilibration.log # create a TPR file, integrate restraints %(grompp)s -f production.mdp -c equilibration.g96 -p system_restr.top -o production.tpr -maxwarn 10000 -n system.ndx cp system_restr.top minimize.top python computeangles.py -f equilibration.g96 -s production.tpr -d $RANSEED python restraint_topology.py -n equilibration -p . # production with restraints %(grompp)s -f production.mdp -c equilibration_restr.g96 -p minimize_restr.top -o production.tpr -maxwarn 10000 -n system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() write_file(os.path.join(complex_path, 'run.sh'), contents) return
def findLigandEnergy(self, working_directory, state): """Runs findEnergy on all of the ligands ARGUMENTS working_directory (string) - the current working directory gromacs_directory (string) - the directory containing gromacs ligand_name_list (array of ) - the list of ligands to be analyzed xvg_values (array of integers) - the array containing the desired xvg_values state (string) - initial/mutatedInitial/mutatedFinal RETURNS ligand (array) - returns the array containing all of the energy terms for all of the comparisons for a single state """ os.chdir(working_directory) n = len(self.xvg_values.split()) + 1 ligand = array([]) # Initial state calculation if state == 'initial': print 'Minimizing Initial' working_directory = os.path.join(working_directory, 'initial') if not os.path.exists(working_directory): commands.getoutput('mkdir %s'%(working_directory)) # Runs findEnergy and appends values to array for i in range(len(self.ligand_name_list)): print 'Minimizing %s'%(self.ligand_name_list[i]) new_working_directory = os.path.join(working_directory, self.ligand_name_list[i]) if not os.path.exists(new_working_directory): commands.getoutput('mkdir %s'%(new_working_directory)) commands.getoutput('cp %s %s/minimize.mdp'%(self.mdp, new_working_directory)) commands.getoutput('cp %s %s/system.gro'%(self.gros[i], new_working_directory)) commands.getoutput('cp %s %s/system.top'%(self.originaltops[i], new_working_directory)) if self.originalitps != None: commands.getoutput('cp %s %s'%(self.originalitps[i], new_working_directory)) os.chdir(new_working_directory) # Sets initial state parameters mdp = MdpFile('minimize.mdp') mdp.setParameter('free-energy', 'no') mdp.setParameter('nsteps', '0') mdp.write('minimize.mdp') line = findEnergy(self.grompp, self.mdrun, self.g_energy, 'minimize.mdp', 'system.gro', 'system.top', self.xvg_values) ligand = append(ligand.reshape(len(ligand), n), line.reshape(1, n), axis=0) # Mutated Initial calculation elif state == 'mutatedInitial': print 'Minimizing Initial Mutation' working_directory = os.path.join(working_directory,'initialmutation') if not os.path.exists(working_directory): commands.getoutput('mkdir %s'%(working_directory)) expanded_ligand_list = list() expanded_gros_list = list() for i in range(len(self.ligand_name_list)): for j in range(i+1, len(self.ligand_name_list)): expanded_ligand_list.append(self.ligand_name_list[i]) expanded_ligand_list.append(self.ligand_name_list[j]) expanded_gros_list.append(self.gros[i]) expanded_gros_list.append(self.gros[j]) # Runs findEnergy and appends values to array for i in range(len(expanded_ligand_list)): if i%2 == 0: comparison = '%s-%s'%(expanded_ligand_list[i], expanded_ligand_list[i+1]) working_directory = os.path.join(working_directory, comparison) commands.getoutput('mkdir %s'%(working_directory)) print 'Minimizing %s in pair %s'%(expanded_ligand_list[i], comparison) new_working_directory = os.path.join(working_directory, expanded_ligand_list[i]) if not os.path.exists(new_working_directory): commands.getoutput('mkdir %s'%(new_working_directory)) commands.getoutput('cp %s %s/minimize.mdp'%(self.mdp, new_working_directory)) commands.getoutput('cp %s %s/system.gro'%(expanded_gros_list[i], new_working_directory)) commands.getoutput('cp %s %s/system.top'%(self.relativetops[i], new_working_directory)) if self.relativeitps != None: commands.getoutput('cp %s %s'%(self.relativeitps[i], new_working_directory)) os.chdir(new_working_directory) # Sets mutated initial state parameters mdp = MdpFile('minimize.mdp') mdp.setParameter('free-energy', 'yes') mdp.setParameter('init-lambda', '0') mdp.setParameter('nsteps','0') mdp.write('minimize.mdp') line = findEnergy(self.grompp, self.mdrun, self.g_energy, 'minimize.mdp', 'system.gro', 'system.top', self.xvg_values) ligand = append(ligand.reshape(len(ligand), n), line.reshape(1, n), axis=0) # Mutated Final calculation elif state == 'mutatedFinal': print 'Minimizing Final Mutation' working_directory = os.path.join(working_directory,'finalmutation') if not os.path.exists(working_directory): commands.getoutput('mkdir %s'%(working_directory)) expanded_ligand_list = list() expanded_gros_list = list() for i in range(len(self.ligand_name_list)): for j in range(i+1, len(self.ligand_name_list)): expanded_ligand_list.append(self.ligand_name_list[i]) expanded_ligand_list.append(self.ligand_name_list[j]) expanded_gros_list.append(self.gros[i]) expanded_gros_list.append(self.gros[j]) for i in range(len(expanded_ligand_list)): if i%2 == 0: comparison = '%s-%s'%(expanded_ligand_list[i], expanded_ligand_list[i+1]) commands.getoutput('mkdir %s'%(os.path.join(working_directory, comparison))) print 'Minimizing %s in pair %s'%(expanded_ligand_list[i], comparison) new_working_directory = os.path.join(working_directory,comparison, expanded_ligand_list[i]) if not os.path.exists(new_working_directory): commands.getoutput('mkdir %s'%(new_working_directory)) commands.getoutput('cp %s %s/minimize.mdp'%(self.mdp, new_working_directory)) commands.getoutput('cp %s %s/system.gro'%(expanded_gros_list[i], new_working_directory)) commands.getoutput('cp %s %s/system.top'%(self.relativetops[i], new_working_directory)) if self.relativeitps != None: commands.getoutput('cp %s %s'%(self.relativeitps[i], new_working_directory)) os.chdir(new_working_directory) # Sets mutated final state parameters mdp = MdpFile('minimize.mdp') mdp.setParameter('free-energy', 'yes') mdp.setParameter('init-lambda', '1') mdp.setParameter('nsteps','0') mdp.write('minimize.mdp') if i%2 == 1: if self.matches != None: matchArray = readMci(self.matches[(i-1)/2]) else: matchArray = determineMatchArray(self.ligand_basepath, expanded_ligand_list[i-1], expanded_ligand_list[i]) mutatedGroStructure = GromacsStructure() mutatedGroStructure = mutateGroFile(expanded_gros_list[i-1], expanded_gros_list[i], matchArray) mutatedGroStructure.write('system.gro') modifySolventInTopFile(self.relativetops[i-1], self.relativetops[i], 'system.top') # Runs findEnergy and appends values to array line = findEnergy(self.grompp, self.mdrun, self.g_energy, 'minimize.mdp', 'system.gro', 'system.top', self.xvg_values) ligand = append(ligand.reshape(len(ligand), n), line.reshape(1, n ), axis=0) return ligand
def setup_binding_free_energy(protein_pdb_filename, ligand_filename, work_path, nreplicates_solvent = 1, nreplicates_complex = 1): """Set up generalized ensemble simulation to calculate a protein-ligand binding free energy. ARGUMENTS protein_pdb_filename (string) - filename of PDB file for the protein, without any missing heavy atoms and with appropriate protonation state already assigned ligand_filename (string) - filename of some type OpenEye can read (e.g. mol2) describing the ligand with suitable docked coordinates work_path (string) - directory to place files for binding free energy calculation (created if does not already exist) OPTIONAL ARGUMENTS nreplicates_solvent (int) - number of replicates to set up of solvated ligand (default: 1) nreplicates_complex (int) - number of replicates to set up of the complexed ligand (default: 1) """ # parameters forcefield = 'ffamber96' # forcefield box_clearance_in_nm = 0.3 # clearance from system to box edges (in nm) # DEBUG set to 1.0 # gromacs filenames pdb2gmx = 'pdb2gmx_d' editconf = 'editconf_d' genbox = 'genbox_d' grompp = 'grompp_d' mdrun = 'mdrun_d' # Create directory for binding free energy calculation if it doesn't exist. #DEBUG os.makedirs(work_path) # SET UP PROTEIN TOPOLOGY print "\nConstructing protein topology..." # Create .top and .gro files for protein using pdb2gmx and desired forcefield # look up forcefield index lines = readFile(os.path.join(os.environ['GMXDATA'], 'top', 'FF.dat')) for forcefield_index in range(1, len(lines)): if lines[forcefield_index].find(forcefield) != -1: break forcefield_index -= 1 # run pdb2gmx protein_gro_filename = os.path.join(work_path, 'protein.gro') protein_top_filename = os.path.join(work_path, 'protein.top') command = 'echo %(forcefield_index)d | %(pdb2gmx)s -f %(protein_pdb_filename)s -o %(protein_gro_filename)s -p %(protein_top_filename)s -ignh -H14' % vars() print command #DEBUG output = commands.getoutput(command) #DEBUG print output # SET UP LIGAND TOPOLOGY print "\nConstructing ligand topology..." # Read the ligand into OEMol. ligand = readMolecule(ligand_filename, normalize = True) # Generate GAFF parameters for gromacs for small molecule, using antechamber to generate AM1-BCC charges. ligand_top_filename = os.path.join(work_path,'ligand.top') ligand_gro_filename = os.path.join(work_path,'ligand.gro') #DEBUG parameterizeForGromacs(ligand, topology_filename = ligand_top_filename, coordinate_filename = ligand_gro_filename, charge_model = 'bcc', resname = 'LIG') # Modify gromacs topology file for alchemical free energy calculation. #DEBUG perturbGromacsTopology(os.path.join(work_path,'ligand.top'), ligand) # SET UP SOLVATED LIGAND print "\nSetting up solvated ligand..." # Create directory to contain ligand in solution. solvated_ligand_path = os.path.join(work_path, 'solvated-ligand') #DEBUG os.makedirs(solvated_ligand_path) # Convert gromacs topology to an .itp file suitable for inclusion. top_to_itp(os.path.join(work_path,'ligand.top'), os.path.join(solvated_ligand_path,'solute.itp'), moleculetype = 'solute') # write enlarged box for solvent system_gro_filename = os.path.join(solvated_ligand_path, 'system.gro') system_top_filename = os.path.join(solvated_ligand_path, 'system.top') command = '%(editconf)s -f %(ligand_gro_filename)s -o %(system_gro_filename)s -bt octahedron -d %(box_clearance_in_nm)f' % vars() print command output = commands.getoutput(command) print output # write topology for system contents = """ ; amber forcefield #include "ffamber03.itp" ; my molecule #include "solute.itp" ; TIP3P water #include "ffamber_tip3p.itp" [ system ] solute [ molecules ] ; Compound nmols solute 1 """ % vars() writeFile(system_top_filename, contents) # solvate command = '%(genbox)s -cp %(system_gro_filename)s -cs ffamber_tip3p.gro -o %(system_gro_filename)s -p %(system_top_filename)s' % vars() print command output = commands.getoutput(command) print output # construct .mdp files mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'output'])) mdpfile.write(os.path.join(solvated_ligand_path, 'minimization-unconstrained.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'constraints', 'output'])) mdpfile.write(os.path.join(solvated_ligand_path, 'minimization-constrained.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(solvated_ligand_path, 'production.mdp')) # write run script contents = """\ #/bin/tcsh source /Users/jchodera/local/gromacs-3.1.4-fe/i386-apple-darwin8.11.1/bin/GMXRC.csh # unconstrained minimization %(grompp)s -f minimization-unconstrained.mdp -c system.gro -p system.top -o minimization-unconstrained.tpr -maxwarn 10000 %(mdrun)s -s minimization-unconstrained.tpr -x minimization-unconstrained.xtc -c minimized-unconstrained.gro -e minimization-unconstrained.edr -g minimization-unconstrained.log # constrained minimization %(grompp)s -f minimization-constrained.mdp -c minimized-unconstrained.gro -p system.top -o minimization-constrained.tpr -maxwarn 10000 %(mdrun)s -s minimization-constrained.tpr -x minimization-constrained.xtc -c minimized-constrained.gro -e minimization-constrained.edr -g minimization-constrained.log # production %(grompp)s -f production.mdp -c minimized-unconstrained.gro -p system.top -o production.tpr -maxwarn 10000 %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.gro -e production.edr -g production.log echo 0 | trjconv_d -f production.xtc -o production.pdb -s production.tpr """ % vars() writeFile(os.path.join(solvated_ligand_path, 'run.sh'), contents) # SET UP SOLVATED COMPLEX # Create directory to contain complex. complex_path = os.path.join(work_path, 'solvated-complex') #DEBUG os.makedirs(complex_path) # Merge protein and liand .top files. complex_top_filename = os.path.join(complex_path, 'complex.top') complex_gro_filename = os.path.join(complex_path, 'complex.gro') merge_protein_ligand_topologies(protein_top_filename, protein_gro_filename, ligand_top_filename, ligand_gro_filename, complex_top_filename, complex_gro_filename) # Alter topology file to use ffamber TIP3P. # system.useTIP3P(complex_top_filename) # Determine total charge. total_charge = totalCharge(complex_top_filename) print "total_charge = %f" % total_charge # Create a System object to help us out. system = System(protein_pdb_filename, finalOutputDir = complex_path, finalOutputName = "protein", useff = forcefield) system.setup.setSaltConditions('MgCl2', 0.010) system.setup.set_boxType = 'octahedron' system.setup.set_boxSoluteDistance(box_clearance_in_nm) system.files.topfile = complex_top_filename system.totalChargeBeforeIons = total_charge # Create a periodic boundary conditions box. command = '%(editconf)s -bt octahedron -f %(complex_gro_filename)s -o %(complex_gro_filename)s -d %(box_clearance_in_nm)f' % vars() output = commands.getoutput(command) print output # solvate the box with TIP3P water command = '%(genbox)s -cp %(complex_gro_filename)s -cs ffamber_tip3p.gro -o %(complex_gro_filename)s -p %(complex_top_filename)s' % vars() output = commands.getoutput(command) print output # calculate how many ions to add to the box [np, nn, nwaters] = system.counterions() print "Adding %(np)d positive and %(nn)d negative to %(nwaters)d waters" % vars() # minimize the system ### make a tpr file with grompp #grompp = '%s/grompp -f %s -c %s -o %s -p %s '%(os.environ['GMXPATH'], self.files.mdpfile_Minimization, self.files.grofile, self.files.tprfile, self.files.topfile) #self.rungmx( grompp, mockrun=self.mockrun, checkForFatalErrors=self.checkForFatalErrors ) ### run minimization #minimize = '%s/mdrun -v -s %s -c %s '%(os.environ['GMXPATH'], self.files.tprfile, self.files.next_gro() ) #self.rungmx( minimize, mockrun=self.mockrun, checkForFatalErrors=self.checkForFatalErrors ) #self.files.increment_gro() # must increment filename for any new gmx file # do the rest of the preparation steps #self.postSolvationPreparationSteps() # construct .mdp files mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'output'])) mdpfile.write(os.path.join(complex_path, 'minimization-unconstrained.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'minimization', 'nonbonded-solvent', 'constraints', 'output'])) mdpfile.write(os.path.join(complex_path, 'minimization-constrained.mdp')) mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'free-energy', 'output'])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(complex_path, 'production.mdp')) # write run script for minimization and production contents = """\ #/bin/tcsh source /Users/jchodera/local/gromacs-3.1.4-fe/i386-apple-darwin8.11.1/bin/GMXRC.csh # unconstrained minimization %(grompp)s -f minimization-unconstrained.mdp -c system.gro -p system.top -o minimization-unconstrained.tpr -maxwarn 10000 %(mdrun)s -s minimization-unconstrained.tpr -x minimization-unconstrained.xtc -c minimized-unconstrained.gro -e minimization-unconstrained.edr -g minimization-unconstrained.log # constrained minimization %(grompp)s -f minimization-constrained.mdp -c minimized-unconstrained.gro -p system.top -o minimization-constrained.tpr -maxwarn 10000 %(mdrun)s -s minimization-constrained.tpr -x minimization-constrained.xtc -c minimized-constrained.gro -e minimization-constrained.edr -g minimization-constrained.log # production %(grompp)s -f production.mdp -c minimized-unconstrained.gro -p system.top -o production.tpr -maxwarn 10000 %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.gro -e production.edr -g production.log echo 0 | trjconv_d -f production.xtc -o production.pdb -s production.tpr """ % vars() writeFile(os.path.join(complex_path, 'run.sh'), contents) # Convert gromacs topology to an .itp file suitable for inclusion. # top_to_itp(os.path.join(molecule_path,'solute.top'), os.path.join(molecule_path,'solute.itp'), moleculetype = molecule_name) return
def findLigandEnergy(self, working_directory, state): """Runs findEnergy on all of the ligands ARGUMENTS working_directory (string) - the current working directory gromacs_directory (string) - the directory containing gromacs ligand_name_list (array of ) - the list of ligands to be analyzed xvg_values (array of integers) - the array containing the desired xvg_values state (string) - initial/mutatedInitial/mutatedFinal RETURNS ligand (array) - returns the array containing all of the energy terms for all of the comparisons for a single state """ os.chdir(working_directory) n = len(self.xvg_values.split()) + 1 ligand = array([]) # Initial state calculation if state == 'initial': print 'Minimizing Initial' working_directory = os.path.join(working_directory, 'initial') if not os.path.exists(working_directory): commands.getoutput('mkdir %s' % (working_directory)) # Runs findEnergy and appends values to array for i in range(len(self.ligand_name_list)): print 'Minimizing %s' % (self.ligand_name_list[i]) new_working_directory = os.path.join(working_directory, self.ligand_name_list[i]) if not os.path.exists(new_working_directory): commands.getoutput('mkdir %s' % (new_working_directory)) commands.getoutput('cp %s %s/minimize.mdp' % (self.mdp, new_working_directory)) commands.getoutput('cp %s %s/system.gro' % (self.gros[i], new_working_directory)) commands.getoutput( 'cp %s %s/system.top' % (self.originaltops[i], new_working_directory)) if self.originalitps != None: commands.getoutput( 'cp %s %s' % (self.originalitps[i], new_working_directory)) os.chdir(new_working_directory) # Sets initial state parameters mdp = MdpFile('minimize.mdp') mdp.setParameter('free-energy', 'no') mdp.setParameter('nsteps', '0') mdp.write('minimize.mdp') line = findEnergy(self.grompp, self.mdrun, self.g_energy, 'minimize.mdp', 'system.gro', 'system.top', self.xvg_values) ligand = append(ligand.reshape(len(ligand), n), line.reshape(1, n), axis=0) # Mutated Initial calculation elif state == 'mutatedInitial': print 'Minimizing Initial Mutation' working_directory = os.path.join(working_directory, 'initialmutation') if not os.path.exists(working_directory): commands.getoutput('mkdir %s' % (working_directory)) expanded_ligand_list = list() expanded_gros_list = list() for i in range(len(self.ligand_name_list)): for j in range(i + 1, len(self.ligand_name_list)): expanded_ligand_list.append(self.ligand_name_list[i]) expanded_ligand_list.append(self.ligand_name_list[j]) expanded_gros_list.append(self.gros[i]) expanded_gros_list.append(self.gros[j]) # Runs findEnergy and appends values to array for i in range(len(expanded_ligand_list)): if i % 2 == 0: comparison = '%s-%s' % (expanded_ligand_list[i], expanded_ligand_list[i + 1]) working_directory = os.path.join(working_directory, comparison) commands.getoutput('mkdir %s' % (working_directory)) print 'Minimizing %s in pair %s' % (expanded_ligand_list[i], comparison) new_working_directory = os.path.join(working_directory, expanded_ligand_list[i]) if not os.path.exists(new_working_directory): commands.getoutput('mkdir %s' % (new_working_directory)) commands.getoutput('cp %s %s/minimize.mdp' % (self.mdp, new_working_directory)) commands.getoutput( 'cp %s %s/system.gro' % (expanded_gros_list[i], new_working_directory)) commands.getoutput( 'cp %s %s/system.top' % (self.relativetops[i], new_working_directory)) if self.relativeitps != None: commands.getoutput( 'cp %s %s' % (self.relativeitps[i], new_working_directory)) os.chdir(new_working_directory) # Sets mutated initial state parameters mdp = MdpFile('minimize.mdp') mdp.setParameter('free-energy', 'yes') mdp.setParameter('init-lambda', '0') mdp.setParameter('nsteps', '0') mdp.write('minimize.mdp') line = findEnergy(self.grompp, self.mdrun, self.g_energy, 'minimize.mdp', 'system.gro', 'system.top', self.xvg_values) ligand = append(ligand.reshape(len(ligand), n), line.reshape(1, n), axis=0) # Mutated Final calculation elif state == 'mutatedFinal': print 'Minimizing Final Mutation' working_directory = os.path.join(working_directory, 'finalmutation') if not os.path.exists(working_directory): commands.getoutput('mkdir %s' % (working_directory)) expanded_ligand_list = list() expanded_gros_list = list() for i in range(len(self.ligand_name_list)): for j in range(i + 1, len(self.ligand_name_list)): expanded_ligand_list.append(self.ligand_name_list[i]) expanded_ligand_list.append(self.ligand_name_list[j]) expanded_gros_list.append(self.gros[i]) expanded_gros_list.append(self.gros[j]) for i in range(len(expanded_ligand_list)): if i % 2 == 0: comparison = '%s-%s' % (expanded_ligand_list[i], expanded_ligand_list[i + 1]) commands.getoutput( 'mkdir %s' % (os.path.join(working_directory, comparison))) print 'Minimizing %s in pair %s' % (expanded_ligand_list[i], comparison) new_working_directory = os.path.join(working_directory, comparison, expanded_ligand_list[i]) if not os.path.exists(new_working_directory): commands.getoutput('mkdir %s' % (new_working_directory)) commands.getoutput('cp %s %s/minimize.mdp' % (self.mdp, new_working_directory)) commands.getoutput( 'cp %s %s/system.gro' % (expanded_gros_list[i], new_working_directory)) commands.getoutput( 'cp %s %s/system.top' % (self.relativetops[i], new_working_directory)) if self.relativeitps != None: commands.getoutput( 'cp %s %s' % (self.relativeitps[i], new_working_directory)) os.chdir(new_working_directory) # Sets mutated final state parameters mdp = MdpFile('minimize.mdp') mdp.setParameter('free-energy', 'yes') mdp.setParameter('init-lambda', '1') mdp.setParameter('nsteps', '0') mdp.write('minimize.mdp') if i % 2 == 1: if self.matches != None: matchArray = readMci(self.matches[(i - 1) / 2]) else: matchArray = determineMatchArray( self.ligand_basepath, expanded_ligand_list[i - 1], expanded_ligand_list[i]) mutatedGroStructure = GromacsStructure() mutatedGroStructure = mutateGroFile( expanded_gros_list[i - 1], expanded_gros_list[i], matchArray) mutatedGroStructure.write('system.gro') modifySolventInTopFile(self.relativetops[i - 1], self.relativetops[i], 'system.top') # Runs findEnergy and appends values to array line = findEnergy(self.grompp, self.mdrun, self.g_energy, 'minimize.mdp', 'system.gro', 'system.top', self.xvg_values) ligand = append(ligand.reshape(len(ligand), n), line.reshape(1, n), axis=0) return ligand
def setupHydrationCalculation(solute, nreplicates=1, verbose=True, jobname="hydration"): """Set up an absolute alchemical hydration free energy calculation for the given molecule. ARGUMENTS solute (OEMol) - the molecule for which hydration free energy is to be computed (with fully explicit hydrogens) in the desired protonation state. OPTIONAL ARGUMENTS nreplicates (integer) - the number of replicates to set up (default: 1) verbose (boolean) - if True, extra debug information will be printed (default: True) jobname (string) - string to use for job name (default: "hydration") NOTES A directory will be created 'molecules/[molecule name]' as obtained from molecule.GetTitle(). """ # get current directory current_path = os.getcwd() # Center the solute molecule. OECenter(solute) # get molecule name solute_name = molecule.GetTitle() if verbose: print solute_name # create molecule path/directory work_path = os.path.abspath(os.path.join("molecules", solute_name)) os.makedirs(work_path) # # Write mol2 file for the molecule. # writeMolecule(solute, os.path.join(solute_path, 'solute.mol2')) # # Write GAFF parameters for gromacs, using antechamber to generate AM1-BCC charges. # parameterizeForGromacs(molecule, topology_filename = os.path.join(molecule_path,'solute.top'), coordinate_filename = os.path.join(molecule_path,'solute.gro'), charge_model = 'bcc', resname = 'MOL') # # Modify gromacs topology file for alchemical free energy calculation. # perturbGromacsTopology(os.path.join(molecule_path,'solute.top'), molecule) # # Convert gromacs topology to an .itp file suitable for inclusion. # top_to_itp(os.path.join(molecule_path,'solute.top'), os.path.join(molecule_path,'solute.itp'), moleculetype = molecule_name) # get pathnames mdrun = globals()["mdrun"] grompp = globals()["grompp"] editconf = globals()["editconf"] # SET UP SOLUTE TOPOLOGY if verbose: print "\nCONSTRUCTING SOLUTE TOPOLOGY" # Get formal charge of ligand. solute_charge = formalCharge(solute) if verbose: print "solute formal charge is %d" % solute_charge # Write molecule with explicit hydrogens to mol2 file. print "Writing solute mol2 file..." solute_mol2_filename = os.path.abspath(os.path.join(work_path, "solute.mol2")) writeMolecule(solute, solute_mol2_filename) # Set substructure name (which will become residue name). print "Modifying molecule name..." modifySubstructureName(solute_mol2_filename, "MOL") # Run antechamber to assign GAFF atom types. print "Running antechamber..." os.chdir(work_path) gaff_mol2_filename = os.path.join(work_path, "solute.gaff.mol2") charge_model = "bcc" command = ( "antechamber -i %(solute_mol2_filename)s -fi mol2 -o solute.gaff.mol2 -fo mol2 -c %(charge_model)s -nc %(solute_charge)d > antechamber.out" % vars() ) if verbose: print command output = commands.getoutput(command) if verbose: print output os.chdir(current_path) # Generate frcmod file for additional GAFF parameters. solute_frcmod_filename = os.path.join(work_path, "frcmod.solute") command = "parmchk -i %(gaff_mol2_filename)s -f mol2 -o %(solute_frcmod_filename)s" % vars() if verbose: print command output = commands.getoutput(command) if verbose: print output # Run LEaP to generate topology / coordinates. solute_prmtop_filename = os.path.join(work_path, "solute.prmtop") solute_crd_filename = os.path.join(work_path, "solute.crd") solute_off_filename = os.path.join(work_path, "solute.off") tleap_input_filename = os.path.join(work_path, "setup-solute.leap.in") tleap_output_filename = os.path.join(work_path, "setup-solute.leap.out") contents = ( """ # Load GAFF parameters. source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(solute_frcmod_filename)s # load solute solute = loadMol2 %(gaff_mol2_filename)s # check the solute check solute # report net charge charge solute # save AMBER parameters saveAmberParm solute %(solute_prmtop_filename)s %(solute_crd_filename)s # write .off file saveOff solute %(solute_off_filename)s # exit quit """ % vars() ) write_file(tleap_input_filename, contents) command = "tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s" % vars() output = commands.getoutput(command) # extract total charge solute_charge = commands.getoutput( 'grep "Total unperturbed charge" %(tleap_output_filename)s | cut -c 27-' % vars() ) solute_charge = int(round(float(solute_charge))) # round to nearest whole charge if verbose: print "solute charge is %d" % solute_charge # PREPARE SOLVATED SOLUTE print "\nPREPARING SOLVATED SOLUTE" # create the directory if it doesn't exist solvent_path = os.path.join(work_path, "solvent") if not os.path.exists(solvent_path): os.makedirs(solvent_path) # solvate the solute print "Solvating the solute with tleap..." system_prmtop_filename = os.path.join(solvent_path, "system.prmtop") system_crd_filename = os.path.join(solvent_path, "system.crd") tleap_input_filename = os.path.join(solvent_path, "setup-system.leap.in") tleap_output_filename = os.path.join(solvent_path, "setup-system.leap.out") clearance = globals()["clearance"] # clearance around solute (in A) contents = ( """ source leaprc.ff99 source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(solute_frcmod_filename)s # Load solute. loadOff %(solute_off_filename)s # Create system. system = combine { solute } """ % vars() ) # add counterions if solute_charge != 0: nions = abs(solute_charge) if solute_charge < 0: iontype = "Na+" if solute_charge > 0: iontype = "Cl-" contents += ( """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() ) # contents += ( """ # Solvate in truncated octahedral box. solvateBox system TIP3PBOX %(clearance)f iso # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() ) write_file(tleap_input_filename, contents) command = "tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s" % vars() output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv("MMTOOLSPATH"), "converters", "amb2gmx.pl") system_prefix = os.path.join(solvent_path, "system") os.chdir(solvent_path) command = "%(amb2gmx)s --prmtop system.prmtop --crd system.crd --outname system" % vars() print command output = commands.getoutput(command) print output os.chdir(current_path) # Extract box size. g96_filename = os.path.join(solvent_path, "system.g96") g96_file = open(g96_filename, "r") g96_lines = g96_file.readlines() g96_file.close() box_size = zeros([3], float32) for line_number in range(len(g96_lines)): if g96_lines[line_number][0:3] == "BOX": # parse line with box size in nm line = g96_lines[line_number + 1] elements = line.split() box_size[0] = float(elements[0]) * 10.0 box_size[1] = float(elements[1]) * 10.0 box_size[2] = float(elements[2]) * 10.0 print "box_size = " print box_size # make a PDB file for checking print "Converting system to PDB..." os.chdir(solvent_path) command = "cat system.crd | ambpdb -p system.prmtop > system.pdb" % vars() output = commands.getoutput(command) print output os.chdir(current_path) # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(solvent_path, "system.top") lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, "atoms") for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if nelements < 8: continue # parse line atom = dict() atom["nr"] = int(elements[0]) atom["type"] = elements[1] atom["resnr"] = int(elements[2]) atom["residue"] = elements[3] atom["atom"] = elements[4] atom["cgnr"] = int(elements[5]) atom["charge"] = float(elements[6]) atom["mass"] = float(elements[7]) # add those atoms in the solute to our list if atom["residue"] == "MOL": perturb_atom_indices.append(atom["nr"]) perturbGromacsTopology( system_top_filename, solute, perturb_torsions=True, perturb_vdw=True, perturb_charges=True, perturb_atom_indices=perturb_atom_indices, ) # set up replicates for replicate in range(nreplicates): # Create replicate directory. working_path = os.path.join(solvent_path, "%d" % replicate) os.makedirs(working_path) # TODO: Modify solute coordinates in system.g96 to cycle through available conformations. # set up mdp files print "Writing mdp files for replicate %d..." % replicate mdpfile = MdpFile(compose_blocks(["header", "minimization", "nonbonded-solvent", "constraints", "output"])) mdpfile.write(os.path.join(working_path, "minimize.mdp")) mdpfile = MdpFile( compose_blocks( ["header", "dynamics", "nonbonded-solvent", "constraints", "thermostat", "barostat", "output"] ) ) mdpfile.setParameter("nsteps", "10000") # 20 ps equilibration mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(working_path, "equilibration.mdp")) mdpfile = MdpFile( compose_blocks( [ "header", "dynamics", "nonbonded-solvent", "constraints", "thermostat", "barostat", "free-energy", "output", ] ) ) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(working_path, "production.mdp")) # write run script print "Writing run script..." solvent_path = os.path.abspath(solvent_path) contents = ( """\ set#!/bin/tcsh #BSUB -J %(jobname)s_solvent #BSUB -o %(working_path)s/outfile.%%J #BSUB -e %(working_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source $GMXRC cd %(working_path)s # constrained minimize %(grompp)s -f minimize.mdp -c ../system.g96 -p ../system.top -o minimize.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # equilibration %(grompp)s -f equilibration.mdp -c minimize.g96 -p ../system.top -o equilibration.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.g96 -e equilibration.edr -g equilibration.log # production %(grompp)s -f production.mdp -c equilibration.g96 -p ../system.top -o production.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() ) write_file(os.path.join(working_path, "run.sh"), contents) # SET UP VACUUM SIMULATION # construct pathname for vacuum simulations vacuum_path = os.path.join(work_path, "vacuum") if not os.path.exists(vacuum_path): os.makedirs(vacuum_path) # solvate the solute print "Preparing vacuum solute with tleap..." system_prmtop_filename = os.path.join(vacuum_path, "system.prmtop") system_crd_filename = os.path.join(vacuum_path, "system.crd") tleap_input_filename = os.path.join(vacuum_path, "setup-system.leap.in") tleap_output_filename = os.path.join(vacuum_path, "setup-system.leap.out") clearance = 50.0 # clearance in A contents = ( """ source leaprc.ff99 source leaprc.gaff # load antechamber-generated additional parameters mods = loadAmberParams %(solute_frcmod_filename)s # Load solute. loadOff %(solute_off_filename)s # Create system. system = combine { solute } """ % vars() ) # add counterions if solute_charge != 0: nions = abs(solute_charge) if solute_charge < 0: iontype = "Na+" if solute_charge > 0: iontype = "Cl-" contents += ( """ # Add counterions. addions system %(iontype)s %(nions)d """ % vars() ) # contents += ( """ # Create big box. setBox system centers %(clearance)f iso # Check the system check system # Write the system saveamberparm system %(system_prmtop_filename)s %(system_crd_filename)s """ % vars() ) write_file(tleap_input_filename, contents) command = "tleap -f %(tleap_input_filename)s > %(tleap_output_filename)s" % vars() output = commands.getoutput(command) # convert to gromacs print "Converting to gromacs..." amb2gmx = os.path.join(os.getenv("MMTOOLSPATH"), "converters", "amb2gmx.pl") os.chdir(vacuum_path) command = "%(amb2gmx)s --prmtop system.prmtop --crd system.crd --outname system" % vars() print command output = commands.getoutput(command) print output os.chdir(current_path) # make a PDB file for checking print "Converting system to PDB..." os.chdir(vacuum_path) command = "cat system.crd | ambpdb -p system.prmtop > system.pdb" % vars() output = commands.getoutput(command) print output os.chdir(current_path) # write enlarged box for solvent because LEaP doesn't do it right. system_g96_filename = os.path.join(vacuum_path, "system.g96") command = "%s -f %s -o %s -bt cubic -box %f %f %f -center 0.0 0.0 0.0" % ( editconf, system_g96_filename, system_g96_filename, box_size[0] / 10.0, box_size[1] / 10.0, box_size[2] / 10.0, ) print command output = commands.getoutput(command) print output # set up perturbation print "Modifying topology file for perturbation..." system_top_filename = os.path.join(vacuum_path, "system.top") lines = read_file(system_top_filename) perturb_atom_indices = list() indices = extract_section(lines, "atoms") nions = 0 for index in indices: # extract the line line = stripcomments(lines[index]) # parse the line elements = line.split() nelements = len(elements) # skip if not all elements found if nelements < 8: continue # parse line atom = dict() atom["nr"] = int(elements[0]) atom["type"] = elements[1] atom["resnr"] = int(elements[2]) atom["residue"] = elements[3] atom["atom"] = elements[4] atom["cgnr"] = int(elements[5]) atom["charge"] = float(elements[6]) atom["mass"] = float(elements[7]) # DEBUG # add those atoms in the solute to our list if atom["residue"] == "MOL": perturb_atom_indices.append(atom["nr"]) # add counterions to balance solute if ((atom["residue"] == "Na+") or (atom["residue"] == "Cl-")) and (nions < abs(solute_charge)): print "WARNING: Solute has net charge of %(solute_charge)d -- will perturb counterions too." % vars() perturb_atom_indices.append(atom["nr"]) nions += 1 perturbGromacsTopology( system_top_filename, solute, perturb_torsions=True, perturb_vdw=True, perturb_charges=True, perturb_atom_indices=perturb_atom_indices, ) # construct replicates for replicate in range(nreplicates): # Create replicate path. working_path = os.path.join(vacuum_path, "%d" % replicate) os.makedirs(working_path) # TODO: Modify solute coordinates in system.g96 to cycle through available conformations. # construct .mdp files print "Writing mdp files for replicate %d..." % replicate mdpfile = MdpFile(compose_blocks(["header", "minimization", "nonbonded-vacuum", "constraints", "output"])) cutoff = box_size.min() / 10.0 / 2.0 - 0.0001 # compute cutoff mdpfile.setParameter("rlist", "%f" % cutoff) mdpfile.setParameter("rvdw", "%f" % cutoff) mdpfile.setParameter("rcoulomb", "%f" % cutoff) mdpfile.write(os.path.join(working_path, "minimize.mdp")) mdpfile = MdpFile( compose_blocks( ["header", "dynamics", "nonbonded-vacuum", "constraints", "thermostat", "free-energy", "output"] ) ) mdpfile.randomizeSeed() # randomize velocities mdpfile.setParameter("rlist", "%f" % cutoff) mdpfile.setParameter("rvdw", "%f" % cutoff) mdpfile.setParameter("rcoulomb", "%f" % cutoff) mdpfile.write(os.path.join(working_path, "production.mdp")) # write shell script for minimization and production contents = ( """\ #!/bin/tcsh #BSUB -J %(jobname)s_vacuum #BSUB -o %(working_path)s/outfile.%%J #BSUB -e %(working_path)s/errfile.%%J #BSUB -n 1 #BSUB -M 2000000 #BSUB -W 168:0 source $GMXRC cd %(working_path)s # constrained minimize %(grompp)s -f minimize.mdp -c ../system.g96 -p ../system.top -o minimize.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s minimize.tpr -x minimize.xtc -c minimize.g96 -e minimize.edr -g minimize.log # production %(grompp)s -f production.mdp -c minimize.g96 -p ../system.top -o production.tpr -maxwarn 10000 -n ../system.ndx %(mdrun)s -s production.tpr -o production.trr -x production.xtc -c production.g96 -e production.edr -g production.log # signal completion mv run.sh run.sh.done """ % vars() ) write_file(os.path.join(working_path, "run.sh"), contents) return
def setupHydrationCalculation(molecule): """ """ # get current directory current_path = os.getcwd() # Center the molecule. OECenter(molecule) # get molecule name molecule_name = molecule.GetTitle() print molecule_name # create molecule path/directory molecule_path = os.path.abspath(os.path.join('molecules', molecule_name)) os.makedirs(molecule_path) # Write mol2 file for the molecule. writeMolecule(molecule, os.path.join(molecule_path, 'solute.mol2')) # Write GAFF parameters for gromacs, using antechamber to generate AM1-BCC charges. parameterizeForGromacs( molecule, topology_filename=os.path.join(molecule_path, 'solute.top'), coordinate_filename=os.path.join(molecule_path, 'solute.gro'), charge_model='bcc', resname='MOL') # Modify gromacs topology file for alchemical free energy calculation. perturbGromacsTopology(os.path.join(molecule_path, 'solute.top'), molecule) # Convert gromacs topology to an .itp file suitable for inclusion. top_to_itp(os.path.join(molecule_path, 'solute.top'), os.path.join(molecule_path, 'solute.itp'), moleculetype=molecule_name) # SET UP VACUUM SIMULATION # construct pathname for vacuum simulations vacuum_path = os.path.join(molecule_path, 'vacuum') os.mkdir(vacuum_path) os.chdir(vacuum_path) # create molecule in enlarged box command = 'editconf_d -f ../solute.gro -o system.gro -bt cubic -d 50.0 -center 0.0 0.0 0.0' print command output = commands.getoutput(command) print output # create topology file topology_contents = """ ; amber forcefield #include "ffamber03.itp" ; my molecule #include "../solute.itp" [ system ] %(molecule_name)s in vacuum [ molecules ] ; Compound nmols %(molecule_name)s 1 """ % vars() writeFile('system.top', topology_contents) # construct .mdp files mdpfile = MdpFile( compose_blocks( ['header', 'minimization', 'nonbonded-vacuum', 'output'])) mdpfile.write(os.path.join(vacuum_path, 'minimization-unconstrained.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'minimization', 'nonbonded-vacuum', 'constraints', 'output' ])) mdpfile.write(os.path.join(vacuum_path, 'minimization-constrained.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-vacuum', 'constraints', 'thermostat', 'free-energy', 'output' ])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(vacuum_path, 'production.mdp')) # write shell script for minimization and production contents = """\ #/bin/tcsh source /Users/jchodera/local/gromacs-3.1.4-fe/i386-apple-darwin8.11.1/bin/GMXRC.csh setenv GROMPP grompp_d setenv MDRUN mdrun_d # unconstrained minimization $GROMPP -f minimization-unconstrained.mdp -c system.gro -p system.top -o minimization-unconstrained.tpr -maxwarn 10000 $MDRUN -s minimization-unconstrained.tpr -x minimization-unconstrained.xtc -c minimized-unconstrained.gro -e minimization-unconstrained.edr -g minimization-unconstrained.log # constrained minimization $GROMPP -f minimization-constrained.mdp -c minimized-unconstrained.gro -p system.top -o minimization-constrained.tpr -maxwarn 10000 $MDRUN -s minimization-constrained.tpr -x minimization-constrained.xtc -c minimized-constrained.gro -e minimization-constrained.edr -g minimization-constrained.log # production $GROMPP -f production.mdp -c minimized-constrained.gro -p system.top -o production.tpr -maxwarn 10000 $MDRUN -v -s production.tpr -o production.trr -x production.xtc -c production.gro -e production.edr -g production.log echo 0 | trjconv_d -f production.xtc -o production.pdb -s production.tpr """ % vars() writeFile(os.path.join(vacuum_path, 'run.sh'), contents) # SET UP SOLVATED CALCULATION # construct pathname for solvent simulations solvated_path = os.path.join(molecule_path, 'solvent') os.mkdir(solvated_path) os.chdir(solvated_path) # write enlarged box for solvent command = 'editconf_d -f ../solute.gro -o solute.gro -bt octahedron -d 1.0 -center 0.0 0.0 0.0' print command output = commands.getoutput(command) print output # write topology topology_contents = """ ; amber forcefield #include "ffamber03.itp" ; my molecule #include "../solute.itp" ; TIP3P water #include "ffamber_tip3p.itp" [ system ] %(molecule_name)s in solvent [ molecules ] ; Compound nmols %(molecule_name)s 1 """ % vars() writeFile('system.top', topology_contents) # solvate command = 'genbox_d -cp solute.gro -cs ffamber_tip3p.gro -o system.gro -p system.top' # command = 'genbox_d -cp solute.gro -cs tip3p-pme-waterbox.gro -o system.gro -p system.top' # use our special tip3p box # command = 'genbox_d -cp solute.gro -cs tip3p-pme-waterbox.gro -o system.gro -p system.top -vdwd 0.0' # insert waters but don't cull overlap print command output = commands.getoutput(command) print output # construct .mdp files mdpfile = MdpFile( compose_blocks( ['header', 'minimization', 'nonbonded-solvent', 'output'])) mdpfile.write(os.path.join(solvated_path, 'minimization-unconstrained.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'minimization', 'nonbonded-solvent', 'constraints', 'output' ])) mdpfile.write(os.path.join(solvated_path, 'minimization-constrained.mdp')) # mdpfile = MdpFile(compose_blocks(['header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat-equilibration', 'barostat', 'output'])) # mdpfile.randomizeSeed() # randomize velocities # mdpfile.setParameter('nsteps', '25000') # 10 ps equilibration # mdpfile.write(os.path.join(solvated_path, 'equilibration.mdp')) mdpfile = MdpFile( compose_blocks([ 'header', 'dynamics', 'nonbonded-solvent', 'constraints', 'thermostat', 'barostat', 'free-energy', 'output' ])) mdpfile.randomizeSeed() # randomize velocities mdpfile.write(os.path.join(solvated_path, 'production.mdp')) # write run script contents = """\ #/bin/tcsh source /Users/jchodera/local/gromacs-3.1.4-fe/i386-apple-darwin8.11.1/bin/GMXRC.csh setenv GROMPP grompp_d setenv MDRUN mdrun_d # unconstrained minimization $GROMPP -f minimization-unconstrained.mdp -c system.gro -p system.top -o minimization-unconstrained.tpr -maxwarn 10000 $MDRUN -s minimization-unconstrained.tpr -x minimization-unconstrained.xtc -c minimized-unconstrained.gro -e minimization-unconstrained.edr -g minimization-unconstrained.log # constrained minimization $GROMPP -f minimization-constrained.mdp -c minimized-unconstrained.gro -p system.top -o minimization-constrained.tpr -maxwarn 10000 $MDRUN -s minimization-constrained.tpr -x minimization-constrained.xtc -c minimized-constrained.gro -e minimization-constrained.edr -g minimization-constrained.log # equilibration #$GROMPP -f equilibration.mdp -c minimized-constrained.gro -p system.top -o equilibration.tpr -maxwarn 10000 #$MDRUN -v -s equilibration.tpr -o equilibration.trr -x equilibration.xtc -c equilibration.gro -e equilibration.edr -g equilibration.log #echo 0 | trjconv_d -f equilibration.xtc -o equilibration.pdb -s equilibration.tpr # production $GROMPP -f production.mdp -c minimized-constrained.gro -p system.top -o production.tpr -maxwarn 10000 #$GROMPP -f production.mdp -c equilibration.gro -p system.top -o production.tpr -maxwarn 10000 #$GROMPP -f production.mdp -c system.gro -p system.top -o production.tpr -maxwarn 10000 $MDRUN -v -s production.tpr -o production.trr -x production.xtc -c production.gro -e production.edr -g production.log echo 0 | trjconv_d -f production.xtc -o production.pdb -s production.tpr """ % vars() writeFile(os.path.join(solvated_path, 'run.sh'), contents) # restore working directory os.chdir(current_path) return