def _solvent_amber_files(self, lig1_name, lig1_mol2, lig1_frcmod, prmtop_filename, inpcrd_filename, leaprc='leaprc.gaff'): logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) handler = logging.FileHandler('tleap_solvent_phase.log') logger.addHandler(handler) #Get absolute paths for input/output lig1_mol2 = os.path.abspath(lig1_mol2) lig1_frcmod = os.path.abspath(lig1_frcmod) prmtop_filename = os.path.abspath(prmtop_filename) inpcrd_filename = os.path.abspath(inpcrd_filename) #Work in a temporary directory, on hard coded filenames, to avoid any issues AMBER may have with spaces and other special characters in filenames with mdtraj.utils.enter_temp_directory(): shutil.copy(lig1_mol2, 'file.mol2') shutil.copy(lig1_frcmod, 'file.frcmod') tleap_input = f""" source oldff/leaprc.ff99SB source {leaprc} loadamberparams file.frcmod LIG = loadmol2 file.mol2 check LIG solvateBox LIG TIP3PBOX 10.0 addIons LIG Cl- 5 addIons LIG K+ 5 saveamberparm LIG out.prmtop out.inpcrd quit """ file_handle = open('tleap_commands', 'w') file_handle.writelines(tleap_input) file_handle.close() cmd = f'tleap -f {file_handle.name}' output = getoutput(cmd) logger.debug(output) #Copy back target files shutil.copy('out.prmtop', prmtop_filename) shutil.copy('out.inpcrd', inpcrd_filename) logfile = os.path.abspath('tleap_solvent_phase.log') destination = os.path.abspath('data') shutil.move(logfile, os.path.join(destination, os.path.basename(logfile))) return prmtop_filename, inpcrd_filename
def build_peptide_tleap(amino_acids): """ Use tleap to generate a peptide topology and positions. Parameters ---------- amino_acids : list of str List of amino acids and caps in three-letter names e.g. ['ACE', 'ALA', 'NME'] Returns ------- topology : simtk.openmm.app.Topology object Topology of the amino acid positions : [n, 3] array positions of atoms """ aa_str = " ".join(amino_acids) filename = "".join(amino_acids) tleapstr = """ source oldff/leaprc.ff99SBildn system = sequence {{ {amino_acid} }} saveamberparm system {filename}.prmtop {filename}.inpcrd """.format(amino_acid=aa_str, filename=filename) cwd = os.getcwd() temp_dir = tempfile.mkdtemp() os.chdir(temp_dir) tleap_file = open('tleap_commands', 'w') tleap_file.writelines(tleapstr) tleap_file.close() tleap_cmd_str = "tleap -f %s " % tleap_file.name #call tleap, log output to logger output = getoutput(tleap_cmd_str) logging.debug(output) prmtop = app.AmberPrmtopFile("{filename}.prmtop".format(filename=filename)) inpcrd = app.AmberInpcrdFile("{filename}.inpcrd".format(filename=filename)) topology = prmtop.topology positions = inpcrd.positions os.chdir(cwd) shutil.rmtree(temp_dir) return topology, positions
def build_mixture_prmtop(mol2_filenames, frcmod_filenames, box_filename, prmtop_filename, inpcrd_filename, water_model = 'TIP3P'): """Create a prmtop and inpcrd from a collection of mol2 and frcmod files as well as a single box PDB. We have used this for setting up simulations of neat liquids or binary mixtures. Parameters ---------- mol2_filenames : list(str) Filenames of GAFF flavored mol2 files. Each must contain exactly ONE ligand. frcmod_filenames : str Filename of input GAFF frcmod filenames. box_filename : str Filename of PDB containing an arbitrary box of the mol2 molecules. prmtop_filename : str output prmtop filename. Should have suffix .prmtop inpcrd_filename : str output inpcrd filename. Should have suffix .inpcrd water_model : str, optional. Default: "TIP3P" String specifying water model to be used IF water is present as a component of the mixture. Valid options are currently "TIP3P", "SPC", or None. If None is specified, flexible GAFF-water will be used as for any other solute (old behavior). Returns ------- tleap_commands : str The string of commands piped to tleap for building the prmtop and inpcrd files. This will *already* have been run, but the output can be useful for debugging or archival purposes. However, this will reflect temporary file names for both input and output file as these are used to avoid tleap filename restrictions. Notes ----- This can be easily broken if there are missing, duplicated, or inconsistent ligand residue names in your box, mol2, and frcmod files. You can use mdtraj to edit the residue names with something like this: trj.top.residue(0).name = "L1" """ # Check for one residue name per mol2 file and uniqueness between all mol2 files all_names = set() for filename in mol2_filenames: t = md.load(filename) names = set([r.name for r in t.top.residues]) if len(names) != 1: raise(ValueError("Must have a SINGLE residue name in each mol2 file.")) all_names = all_names.union(list(names)) if len(all_names) != len(mol2_filenames): raise(ValueError("Must have UNIQUE residue names in each mol2 file.")) if len(mol2_filenames) != len(frcmod_filenames): raise(ValueError("Must provide an equal number of frcmod and mol2 file names.")) #Get number of files nfiles = len(mol2_filenames) #Check validity of water model options valid_water = ['TIP3P', 'SPC', None] if not water_model in valid_water: raise(ValueError("Must provide a valid water model.")) #If we are requesting a different water model, check if there is water present if not water_model==None: parmed = import_("parmed") solventIsWater = [] waterPresent = False for i in range(nfiles): mol = parmed.load_file( mol2_filenames[i] ) #Check if it is water by checking GAFF atom names types = [ atom.type for atom in mol.atoms ] if 'oh' in types and types.count('ho')==2 and len(types)==3: solventIsWater.append(True) waterPresent = True else: solventIsWater.append(False) #In this case, if we have any water, we will now work on fewer .mol2 and .frcmod files and instead use the force field files for those. So, reduce nfiles and remove the files we don't need from the .mol2 and .frcmod filename lists #After doing so, go on to interpret the specified water model and compose the water model string needed for tleap if waterPresent: new_mol2_filenames = [] new_frcmod_filenames = [] water_mol2_filenames = [] for i in range( nfiles ): if not solventIsWater[i]: new_mol2_filenames.append( mol2_filenames[i] ) new_frcmod_filenames.append( frcmod_filenames[i] ) else: water_mol2_filenames.append( mol2_filenames[i] ) nfiles = len(new_mol2_filenames) mol2_filenames = new_mol2_filenames frcmod_filenames = new_frcmod_filenames #Now interpret the specified water model and translate into AMBER nomenclature if water_model=='TIP3P': water_model = 'TP3' elif water_model =='SPC': water_model = 'SPC' else: raise(ValueError("Cannot translate specified water model into one of the available models.")) #Compose string for loading specified water molecule water_string = '\n' water_names = [md.load(filename).top.residue(0).name for filename in water_mol2_filenames] for name in water_names: water_string += '%s = %s\n' % (name, water_model ) #Also if not TIP3P, update to source correct frcmod file if water_model == 'SPC': water_string += 'loadamberparams frcmod.spce\n' elif water_model =='TP3': continue else: raise(ValueError("Cannot identify water frcmod file to be loaded.")) #Rename water atoms in box file to match what is expected by AMBER packmol = import_("openmoltools.packmol") packmol.rename_water_atoms(box_filename) else: waterPresent = False #Make temporary, hardcoded filenames for mol2 and frcmod input to avoid tleap filename restrictions tmp_mol2_filenames = [ 'in%d.mol2' % n for n in range(nfiles) ] tmp_frcmod_filenames = [ 'in%d.frcmod' % n for n in range(nfiles) ] #Make temporary, hardcoded filenames for output files to avoid tleap filename restrictions tmp_prmtop_filename = 'out.prmtop' tmp_inpcrd_filename = 'out.inpcrd' tmp_box_filename = 'tbox.pdb' #Build absolute paths of input files so we can use context and temporary directory infiles = mol2_filenames + frcmod_filenames + [box_filename] infiles = [ os.path.abspath(filenm) for filenm in infiles ] #Build absolute paths of output files so we can copy them back prmtop_filename = os.path.abspath( prmtop_filename ) inpcrd_filename = os.path.abspath( inpcrd_filename ) #Use temporary directory and do the setup with mdtraj.utils.enter_temp_directory(): #Copy input files to temporary file names in target directory for (infile, outfile) in zip( infiles, tmp_mol2_filenames+tmp_frcmod_filenames+[tmp_box_filename] ): shutil.copy( infile, outfile) logger.debug('Copying input file %s to %s...\n' % (infile, outfile)) all_names = [md.load(filename).top.residue(0).name for filename in tmp_mol2_filenames] mol2_section = "\n".join("%s = loadmol2 %s" % (all_names[k], filename) for k, filename in enumerate(tmp_mol2_filenames)) #If non-GAFF water is present, load desired parameters for that water as well. if waterPresent: mol2_section += water_string amberparams_section = "\n".join("loadamberparams %s" % (filename) for k, filename in enumerate(tmp_frcmod_filenames)) tleap_commands = TLEAP_TEMPLATE % dict(mol2_section=mol2_section, amberparams_section=amberparams_section, box_filename=tmp_box_filename, prmtop_filename=tmp_prmtop_filename, inpcrd_filename=tmp_inpcrd_filename) print(tleap_commands) file_handle = open('tleap_commands', 'w') file_handle.writelines(tleap_commands) file_handle.close() logger.debug('Running tleap in temporary directory.') cmd = "tleap -f %s " % file_handle.name logger.debug(cmd) output = getoutput(cmd) logger.debug(output) check_for_errors( output, other_errors = ['Improper number of arguments'], ignore_errors = ['unperturbed charge of the unit', 'ignoring the error'] ) #Copy stuff back to right filenames for (tfile, finalfile) in zip( [tmp_prmtop_filename, tmp_inpcrd_filename], [prmtop_filename, inpcrd_filename] ): shutil.copy( tfile, finalfile) return tleap_commands
def run_tleap(molecule_name, gaff_mol2_filename, frcmod_filename, prmtop_filename=None, inpcrd_filename=None, log_debug_output=False): """Run AmberTools tleap to create simulation files for AMBER Parameters ---------- molecule_name : str The name of the molecule gaff_mol2_filename : str GAFF format mol2 filename produced by antechamber frcmod_filename : str Amber frcmod file produced by prmchk prmtop_filename : str, optional, default=None Amber prmtop file produced by tleap, defaults to molecule_name inpcrd_filename : str, optional, default=None Amber inpcrd file produced by tleap, defaults to molecule_name log_debug_output : bool, optional, default=False If true, will send output of tleap to logger. Returns ------- prmtop_filename : str Amber prmtop file produced by tleap inpcrd_filename : str Amber inpcrd file produced by tleap """ if prmtop_filename is None: prmtop_filename = "%s.prmtop" % molecule_name if inpcrd_filename is None: inpcrd_filename = "%s.inpcrd" % molecule_name #Get absolute paths for input/output gaff_mol2_filename = os.path.abspath( gaff_mol2_filename ) frcmod_filename = os.path.abspath( frcmod_filename ) prmtop_filename = os.path.abspath( prmtop_filename ) inpcrd_filename = os.path.abspath( inpcrd_filename ) #Work in a temporary directory, on hard coded filenames, to avoid any issues AMBER may have with spaces and other special characters in filenames with mdtraj.utils.enter_temp_directory(): shutil.copy( gaff_mol2_filename, 'file.mol2' ) shutil.copy( frcmod_filename, 'file.frcmod' ) tleap_input = """ source oldff/leaprc.ff99SB source leaprc.gaff LIG = loadmol2 file.mol2 check LIG loadamberparams file.frcmod saveamberparm LIG out.prmtop out.inpcrd quit """ file_handle = open('tleap_commands', 'w') file_handle.writelines(tleap_input) file_handle.close() cmd = "tleap -f %s " % file_handle.name if log_debug_output: logger.debug(cmd) output = getoutput(cmd) if log_debug_output: logger.debug(output) check_for_errors( output, other_errors = ['Improper number of arguments'] ) #Copy back target files shutil.copy( 'out.prmtop', prmtop_filename ) shutil.copy( 'out.inpcrd', inpcrd_filename ) return prmtop_filename, inpcrd_filename
def run_antechamber(molecule_name, input_filename, charge_method="bcc", net_charge=None, gaff_mol2_filename=None, frcmod_filename=None, input_format='mol2', resname=False, log_debug_output=False): """Run AmberTools antechamber and parmchk2 to create GAFF mol2 and frcmod files. Parameters ---------- molecule_name : str Name of the molecule to be parameterized, will be used in output filenames. ligand_filename : str The molecule to be parameterized. Must be tripos mol2 format. charge_method : str, optional If not None, the charge method string will be passed to Antechamber. net_charge : int, optional If not None, net charge of the molecule to be parameterized. If None, Antechamber sums up partial charges from the input file. gaff_mol2_filename : str, optional, default=None Name of GAFF mol2 filename to output. If None, uses local directory and molecule_name frcmod_filename : str, optional, default=None Name of GAFF frcmod filename to output. If None, uses local directory and molecule_name input_format : str, optional, default='mol2' Format specifier for input file to pass to antechamber. resname : bool, optional, default=False Set the residue name used within output files to molecule_name log_debug_output : bool, optional, default=False If true, will send output of tleap to logger. Returns ------- gaff_mol2_filename : str GAFF format mol2 filename produced by antechamber frcmod_filename : str Amber frcmod file produced by prmchk """ utils = import_("openmoltools.utils") ext = utils.parse_ligand_filename(input_filename)[1] if gaff_mol2_filename is None: gaff_mol2_filename = molecule_name + '.gaff.mol2' if frcmod_filename is None: frcmod_filename = molecule_name + '.frcmod' #Build absolute paths for input and output files gaff_mol2_filename = os.path.abspath( gaff_mol2_filename ) frcmod_filename = os.path.abspath( frcmod_filename ) input_filename = os.path.abspath( input_filename ) def read_file_contents(filename): infile = open(filename, 'r') contents = infile.read() infile.close() return contents #Use temporary directory context to do this to avoid issues with spaces in filenames, etc. with mdtraj.utils.enter_temp_directory(): local_input_filename = 'in.' + input_format shutil.copy( input_filename, local_input_filename ) # Run antechamber. cmd = "antechamber -i %(local_input_filename)s -fi %(input_format)s -o out.mol2 -fo mol2 -s 2" % vars() if charge_method is not None: cmd += ' -c %s' % charge_method if net_charge is not None: cmd += ' -nc %d' % net_charge if resname: cmd += ' -rn %s' % molecule_name if log_debug_output: logger.debug(cmd) output = getoutput(cmd) if not os.path.exists('out.mol2'): msg = "antechamber failed to produce output mol2 file\n" msg += "command: %s\n" % cmd msg += "output:\n" msg += 8 * "----------" + '\n' msg += output msg += 8 * "----------" + '\n' msg += "input mol2:\n" msg += 8 * "----------" + '\n' msg += read_file_contents(local_input_filename) msg += 8 * "----------" + '\n' raise Exception(msg) if log_debug_output: logger.debug(output) # Run parmchk. cmd = "parmchk2 -i out.mol2 -f mol2 -o out.frcmod" if log_debug_output: logger.debug(cmd) output = getoutput(cmd) if not os.path.exists('out.frcmod'): msg = "parmchk2 failed to produce output frcmod file\n" msg += "command: %s\n" % cmd msg += "output:\n" msg += 8 * "----------" + '\n' msg += output msg += 8 * "----------" + '\n' msg += "input mol2:\n" msg += 8 * "----------" + '\n' msg += read_file_contents('out.mol2') msg += 8 * "----------" + '\n' raise Exception(msg) if log_debug_output: logger.debug(output) check_for_errors(output) #Copy back shutil.copy( 'out.mol2', gaff_mol2_filename ) shutil.copy( 'out.frcmod', frcmod_filename ) return gaff_mol2_filename, frcmod_filename
def do_solvate( top_filename, gro_filename, top_solv_filename, gro_solv_filename, box_dim, box_type, water_model, water_top, FF = 'amber99sb-ildn.ff' ): """ This function creates water solvated molecule coordinate files and its corresponding topology PARAMETERS: top_filename: str Topology path/filename gro_filename: str Coordinates path/filename top_solv_filename: str Topology path/filename (solvated system) gro_solv_filename: str Coordinates path/filename (solvated system) box_dim: float cubic box dimension (nm); will be passed to GROMACS wiin .2f format box_type: str box type (string passed to gmx solvate) water_model: str Water model string to tell gmx solvate to use when solvating, i.e. "spc216" water_top: str Water include file to ensure is present in topology file, i.e. "tip3p.itp" FF : str, optional, default = 'amber99sb-ildn.ff' String specifying base force field directory for include files (i.e. 'amber99sb-ildn.ff'). NOTES: ----- Primarily tested on 3 point water models. May need adjustment for other models. """ #Setting up proper environment variables os.environ['GMX_MAXBACKUP'] = '-1' # Avoids unnecessary GROMACS backup files os.environ['GMX_NO_QUOTES'] = '1' # Supresses end-of-file quotes (gcq) #Get absolute paths for input/output top_filename = os.path.abspath( top_filename ) gro_filename = os.path.abspath( gro_filename ) top_solv_filename = os.path.abspath( top_solv_filename ) gro_solv_filename = os.path.abspath( gro_solv_filename ) with mdtraj.utils.enter_temp_directory(): #Work on hard coded filenames in temporary directory shutil.copy( gro_filename, 'in.gro' ) shutil.copy( top_filename, 'out.top' ) #string with the Gromacs 5.0.4 box generating commands cmdbox = 'gmx editconf -f in.gro -o out.gro -c -d %.2f -bt %s' % ( box_dim, box_type) output = getoutput(cmdbox) logger.debug(output) check_for_errors(output) #string with the Gromacs 5.0.4 solvation tool (it is not genbox anymore) cmdsolv = 'gmx solvate -cp out.gro -cs %s -o out.gro -p out.top' % (water_model) output = getoutput(cmdsolv) logger.debug(output) check_for_errors(output) #Insert Force Field specifications ensure_forcefield( 'out.top', 'out.top', FF = FF) #Insert line for water topology portion of the code try: file = open('out.top','r') text = file.readlines() file.close() except: raise NameError('The file out.top is missing' ) #Insert water model wateritp = os.path.join(FF, water_top ) # e.g water_top = 'tip3p.itp' index = 0 while '[ system ]' not in text[index]: index += 1 text[index] = '#include "%s"\n\n' % wateritp + text[index] #Write the topology file try: file = open('out.top','w+') file.writelines( text ) file.close() except: raise NameError('The file %s is missing' % 'out.top') #Check if file exist and is not empty; if os.stat( 'out.gro' ) == 0 or os.stat( 'out.top' ).st_size == 0: raise(ValueError("Solvent insertion failed")) #Copy back files shutil.copy( 'out.gro', gro_solv_filename ) shutil.copy( 'out.top', top_solv_filename ) return
def build_mixture_prmtop(mol2_filenames, frcmod_filenames, box_filename, prmtop_filename, inpcrd_filename): """Create a prmtop and inpcrd from a collection of mol2 and frcmod files as well as a single box PDB. We have used this for setting up simulations of binary mixtures. - Original code by : Chodera Lab / Openmoltools project (https://github.com/choderalab/openmoltools) Parameters ---------- mol2_filenames : list(str) Filenames of GAFF flavored mol2 files. Each must contain exactly ONE ligand. frcmod_filenames : str Filename of input GAFF frcmod filenames. box_filename : str Filename of PDB containing an arbitrary box of the mol2 molecules. prmtop_filename : str output prmtop filename. Should have suffix .prmtop inpcrd_filename : str output inpcrd filename. Should have suffix .inpcrd water_model : str, optional. Default: "TIP3P" String specifying water model to be used IF water is present as a component of the mixture. Valid options are currently "TIP3P", "SPC", or None. If None is specified, flexible GAFF-water will be used as for any other solute (old behavior). Returns ------- tleap_commands : str The string of commands piped to tleap for building the prmtop and inpcrd files. This will *already* have been run, but the output can be useful for debugging or archival purposes. However, this will reflect temporary file names for both input and output file as these are used to avoid tleap filename restrictions. Notes ----- This can be easily broken if there are missing, duplicated, or inconsistent ligand residue names in your box, mol2, and frcmod files. You can use mdtraj to edit the residue names with something like this: trj.top.residue(0).name = "L1" """ # Check for one residue name per mol2 file and uniqueness between all mol2 files all_names = set() for filename in mol2_filenames: t = md.load(filename) names = set([r.name for r in t.top.residues]) if len(names) != 1: raise (ValueError( "Must have a SINGLE residue name in each mol2 file.")) all_names = all_names.union(list(names)) if len(all_names) != len(mol2_filenames): raise (ValueError("Must have UNIQUE residue names in each mol2 file.")) if len(mol2_filenames) != len(frcmod_filenames): raise (ValueError( "Must provide an equal number of frcmod and mol2 file names.")) #Get number of files nfiles = len(mol2_filenames) #Build absolute paths of input files so we can use context and temporary directory infiles = mol2_filenames + frcmod_filenames + [box_filename] infiles = [os.path.abspath(filenm) for filenm in infiles] #Build absolute paths of output files so we can copy them back prmtop_filename = os.path.abspath(prmtop_filename) inpcrd_filename = os.path.abspath(inpcrd_filename) #Use temporary directory and do the setup with md.utils.enter_temp_directory(): all_names = [ md.load(filename).top.residue(0).name for filename in mol2_filenames ] mol2_section = "\n".join("%s = loadmol2 %s" % (all_names[k], filename) for k, filename in enumerate(mol2_filenames)) amberparams_section = "\n".join( "loadamberparams %s" % (filename) for k, filename in enumerate(frcmod_filenames)) tleap_commands = TLEAP_TEMPLATE % dict( mol2_section=mol2_section, amberparams_section=amberparams_section, box_filename=box_filename, prmtop_filename=prmtop_filename, inpcrd_filename=inpcrd_filename) print(tleap_commands) file_handle = open('tleap_commands', 'w') file_handle.writelines(tleap_commands) file_handle.close() logger.debug('Running tleap in temporary directory.') cmd = "tleap -f %s " % file_handle.name logger.debug(cmd) output = getoutput(cmd) logger.debug(output) return tleap_commands