def do_energy_min(pdb, itpfn, outpdb="out.pdb"): # write the topology file with open("topol_em.top", "w") as fh_t: fh_t.write(HEAD_TOP_FILE) fh_t.write("#include " + '"' + itpfn + '"') fh_t.write(BOTTOM_TOP_FILE) # TODO function that checks if files are present gromacs.grompp(f="em.mdp", c=pdb, p="topol_em.top", o="em.tpr", maxwarn="99") gromacs.mdrun(s="em.tpr", c=outpdb)
def mdrun(s, prefix): o = prefix + '.trr' rc, output, junk = gromacs.mdrun(v=True, s=s, o=o, stdout=False, stderr=False) assert rc == 0, "mdrun failed" return o
def rerun_energy(s, o, prefix): e = prefix + '.edr' rc, output, junk = gromacs.mdrun(v=True, s=s, rerun=o, e=e, stdout=False, stderr=False) assert rc == 0, "mdrun failed" xvg = prefix + '.xvg' rc, output, junk = gromacs.g_energy(f=e, o=xvg, input=("Proper-Dih.", "Improper-Dih.", "CMAP-Dih.", "LJ-14", "Coulomb-14", "LJ-(SR)", "Coulomb-(SR)", "Coul.-recip.", "Potential"), stdout=False, stderr=False) assert rc == 0, "g_energy failed" return XVG(xvg).to_df()
def _run_mdrun(self, step_name: str, tpr: GenPath = None ) -> pathlib.Path: """ Run mdrun with the given step_name or explicitly given tpr file. :param step_name: The name of this step :param tpr: Path to the tpr file. If None, the tpr will be found from the dict :attr:`tprs` with the key being `step_name` :return: The Path to the output geometry """ tpr = self.tprs[step_name] if tpr is None else tpr deffnm = '{}-{}-out'.format(self.name, step_name) p_deffnm = self._fp(deffnm) self.deffnms[step_name] = p_deffnm rc, output, junk = gromacs.mdrun(s=tpr, deffnm=deffnm, stdout=False) # Doesn't capture output if failed? self.outputs['run_{}'.format(step_name)] = output gro = p_deffnm.with_suffix('.gro') self.geometries[step_name] = gro return gro
def rerun_energy(s, o, prefix): e = prefix + '.edr' rc, output, junk = gromacs.mdrun(v=True, s=s, rerun=o, e=e, stdout=False, stderr=False) assert rc == 0, "mdrun failed" xvg = prefix + '.xvg' rc, output, junk = gromacs.g_energy( f=e, o=xvg, input=("Proper-Dih.", "Improper-Dih.", "CMAP-Dih.", "LJ-14", "Coulomb-14", "LJ-(SR)", "Coulomb-(SR)", "Coul.-recip.", "Potential"), stdout=False, stderr=False) assert rc == 0, "g_energy failed" return XVG(xvg).to_df()
def energy_minimize(dirname='em', mdp=config.templates['em.mdp'], struct='solvate/ionized.pdb', top='top/system.top', output='em.pdb', deffnm="em", mdrunner=None, **kwargs): """Energy minimize the system. This sets up the system (creates run input files) and also runs ``mdrun_d``. Thus it can take a while. Additional itp files should be in the same directory as the top file. Many of the keyword arguments below already have sensible values. :Keywords: *dirname* set up under directory dirname [em] *struct* input structure (gro, pdb, ...) [solvate/ionized.pdb] *output* output structure (will be put under dirname) [em.pdb] *deffnm* default name for mdrun-related files [em] *top* topology file [top/system.top] *mdp* mdp file (or use the template) [templates/em.mdp] *includes* additional directories to search for itp files *mdrunner* :class:`gromacs.run.MDrunner` class; by defauly we just try :func:`gromacs.mdrun_d` and :func:`gromacs.mdrun` but a MDrunner class gives the user the ability to run mpi jobs etc. [None] *kwargs* remaining key/value pairs that should be changed in the template mdp file, eg ``nstxtcout=250, nstfout=250``. .. note:: If :func:`~gromacs.mdrun_d` is not found, the function falls back to :func:`~gromacs.mdrun` instead. """ structure = realpath(struct) topology = realpath(top) mdp_template = config.get_template(mdp) deffnm = deffnm.strip() # write the processed topology to the default output kwargs.setdefault('pp', 'processed.top') # filter some kwargs that might come through when feeding output # from previous stages such as solvate(); necessary because *all* # **kwargs must be *either* substitutions in the mdp file *or* valid # command line parameters for ``grompp``. kwargs.pop('ndx', None) # mainselection is not used but only passed through; right now we # set it to the default that is being used in all argument lists # but that is not pretty. TODO. mainselection = kwargs.pop('mainselection', '"Protein"') # only interesting when passed from solvate() qtot = kwargs.pop('qtot', 0) mdp = deffnm+'.mdp' tpr = deffnm+'.tpr' logger.info("[%(dirname)s] Energy minimization of struct=%(struct)r, top=%(top)r, mdp=%(mdp)r ..." % vars()) add_mdp_includes(topology, kwargs) if qtot != 0: # At the moment this is purely user-reported and really only here because # it might get fed into the function when using the keyword-expansion pipeline # usage paradigm. wmsg = "Total charge was reported as qtot = %(qtot)g <> 0; probably a problem." % vars() logger.warn(wmsg) warnings.warn(wmsg, category=BadParameterWarning) with in_dir(dirname): unprocessed = gromacs.cbook.edit_mdp(mdp_template, new_mdp=mdp, **kwargs) check_mdpargs(unprocessed) gromacs.grompp(f=mdp, o=tpr, c=structure, p=topology, **unprocessed) mdrun_args = dict(v=True, stepout=10, deffnm=deffnm, c=output) if mdrunner is None: try: gromacs.mdrun_d(**mdrun_args) except (AttributeError, OSError): # fall back to mdrun if no double precision binary wmsg = "No 'mdrun_d' binary found so trying 'mdrun' instead.\n"\ "(Note that energy minimization runs better with mdrun_d.)" logger.warn(wmsg) warnings.warn(wmsg, category=AutoCorrectionWarning) gromacs.mdrun(**mdrun_args) else: # user wants full control and provides simulation.MDrunner **class** # NO CHECKING --- in principle user can supply any callback they like mdrun = mdrunner(**mdrun_args) mdrun.run() # em.gro --> gives 'Bad box in file em.gro' warning --- why?? # --> use em.pdb instead. if not os.path.exists(output): errmsg = "Energy minimized system NOT produced." logger.error(errmsg) raise GromacsError(errmsg) final_struct = realpath(output) logger.info("[%(dirname)s] energy minimized structure %(final_struct)r" % vars()) return {'struct': final_struct, 'top': topology, 'mainselection': mainselection, }
def add_box_mutation(self): """ Function to add the solvent and run a minimization of the local amino acid with the waters included Output: system.gro -- file containing the complete system minimized after the mutation """ # Read the solvent os.system("grep ATOM {path}/solvent/solvent_{itera}.pdb | grep -v ENDMDL > {path}/solvent.pdb".format(path=self.path,itera=self.last_iteration)) # Concatenate complex and system os.system("cat {path}/complex.pdb {path}/solvent.pdb > {path}/system.pdb".format(path=self.path)) rc,sout,serr=gromacs.editconf(f=self.path+"/system.pdb", o=self.path+"/system_mod.pdb", stdout=False) os.system("mv {}/system_mod.pdb {}/system.pdb".format(self.path,self.path)) # Make an index of the system rc,sout,serr=gromacs.make_ndx(f=self.path+"/system.pdb", o=self.path+"/index.ndx", stdout=False, input=('chain {} \n q'.format(self.pep_chain))) # Copy the topol files of the target chains, which are the same always if self.target=="protein": for ch in self.chain_join: os.system("cp {}/topol_Protein_chain_{}.itp {}/system_Protein_chain_{}.itp".format(self.path,ch,self.path,ch)) if self.target=="drug": for ch in self.chain_join: os.system("cp {}/topol_Drug_chain_{}.itp {}/system_Drug_chain_{}.itp".format(self.path,ch,self.path,ch)) # Copy the topol.top to system.top os.system("cp {}/topol.top {}/system.top".format(self.path,self.path)) os.system("cp {}/complex_Protein_chain_{}.itp {}/system_Protein_chain_{}.itp".format(self.path,self.pep_chain,self.path,self.pep_chain)) os.system("sed -i 's/topol_/system_/g' {}/system.top".format(self.path)) # Select water and ions within 0.2 distance of the residue rc,sout,serr=gromacs.make_ndx(f=self.path+"/system.pdb", o=self.path+"/index.ndx", stdout=False, input=('chain {}'.format(self.pep_chain),'q')) rc,sout,serr=gromacs.select(f=self.path+"/system.pdb", n=self.path+"/index.ndx", s=self.path+"/system.pdb", on=self.path+"/index_sol.ndx", stdout=False, select="group Water_and_ions and same residue as within 0.2 of (group ch{} and resnr {})".format(self.pep_chain,self.pep_position)) # Solve the issue with atoms overlapped with the selected residue values=[x.strip() for x in open(self.path+"/index_sol.ndx")] atomsSOL=[] for i,v in enumerate(values): if i!=0: info=v.split() atomsSOL=atomsSOL+info # List of the atoms that will be deleted atomsDelete=[] # Check the overlapped atoms for a in atomsSOL: # Obtain the list of atoms from the index file bash = "awk '$2 == '{}' {{print $6','$7','$8}}' {}/system.pdb".format(a,self.path) coordinates = subprocess.check_output(['bash','-c', bash]) comp=coordinates.strip().split() comparison=[] for c in comp: comparison.append(float(c)) ndComp=np.array(comparison) distancesSOL=[] # Read the structure in biopython parser = PDBParser() structure = parser.get_structure('PEP', self.path+"/system.pdb") model = structure[0] # Check the distances with all the atoms from the selected residue for residue in model[self.pep_chain]: resC=residue.get_resname() resNumber=residue.get_full_id()[3][1] if resNumber==self.pep_position: for atom in residue: idAtom = atom.get_id() if idAtom[0].isdigit() == False: if resC=="ILE" and idAtom=="CD": idAtom="CD1" diff = atom.coord - ndComp diffValue=np.sqrt(np.sum(diff * diff)) distancesSOL.append(float(diffValue)) # Threshold to determine which atoms can be overlapped if min(distancesSOL)<1.0: if a not in atomsDelete: atomsDelete.append(a) # Selection of the final atoms that will be included in the index final_index=[] for element in atomsSOL: flag=0 for delete in atomsDelete: if abs(int(element)-int(delete))<=2: flag=1 if flag==0: final_index.append(element) # Update of the index sol file new_index=open(self.path+"/index_sol2.ndx","w") new_index.write("{}\n".format(values[0])) group=[] counter=1 for ele in final_index: if counter <15: group.append(ele) counter+=1 else: group.append(ele) new_index.write(" ".join(group)+" \n") counter=1 group=[] new_index.write(" ".join(group)+" ") new_index.close() # Update the file os.system("mv {}/index_sol2.ndx {}/index_sol.ndx".format(self.path,self.path)) ref_ndx = NDX() ref_ndx.read(self.path+"/index.ndx") bash="grep '\[' {}/index.ndx | wc -l".format(self.path) number_index = subprocess.check_output(['bash','-c', bash]) index_ref=int(number_index)-1 #index_ref=len(ref_ndx)-1 # Create the side chain index in a template file os.system("echo 'name 0 overlap' > %s/template" %self.path) os.system("echo '\"SideChain\" & \"ch{}\" & r {}' >> {}/template".format(self.pep_chain,str(self.pep_position),self.path)) os.system("echo '\"overlap\" | \"SideChain_&_ch{}_&_r_{}\"' >> {}/template".format(self.pep_chain,str(self.pep_position),self.path)) os.system("echo '\"System\" &! \"overlap_SideChain_&_ch{}_&_r_{}\"' >> {}/template".format(self.pep_chain,str(self.pep_position),self.path)) os.system("echo 'q' >> {}/template".format(self.path)) # Create an index joining both created before os.system("gmx -quiet make_ndx -f {path}/system.pdb -n {path}/index_sol.ndx {path}/index.ndx -o {path}/total_index.ndx < {path}/template".format(path=self.path)) os.system("sed -i 's/System_&_\!overlap_SideChain_&_ch{}_&_r_{}/to_block/g' {}/total_index.ndx".format(self.pep_chain,str(self.pep_position),self.path)) # Generate the gro file rc,sout,serr=gromacs.editconf(f=self.path+"/system.pdb", o=self.path+"/system.gro", stdout=False) # Prepare the files for the minimization and run rc,sout,serr=gromacs.grompp(f=self.path+"/mdp/minim_overlap.mdp", o=self.path+"/systemNEW.tpr", p=self.path+"/system.top", n=self.path+"/total_index.ndx", c=self.path+"/system.gro", stdout=False) gromacs.utilities.unlink_gmx("mdout.mdp") print("Running second minimization ...") rc,sout,serr=gromacs.mdrun(deffnm=self.path+"/systemNEW", stdout=False) # Copy the system.gro file that will be used to run the last minimization os.system("cp {}/systemNEW.gro {}/system.gro".format(self.path,self.path)) os.system("sed -i '$ d' {}/system.gro".format(self.path)) os.system("tail -n1 {path}/npt-pbc.gro >> {path}/system.gro".format(path=self.path)) # Delete temporal files os.system("rm {path}/complex.pdb {path}/solvent.pdb {path}/systemNEW* {path}/template {path}/index.ndx {path}/index_sol.ndx {path}/total_index.ndx *.itp".format(path=self.path))
def run_minim_complex(self,run_minim=False): """ Function to run a local minimization on the side chain that was mutated Arguments: run_minim -- boolean flag that will control if the minimization is run or not Output: complex.pdb -- new complex pdb with the minimization and the new itp files """ # Get the chain with the peptide to generate a novel itp file os.system("python3 {}/src/scores/get_chains.py {}/complex.pdb {}".format(self.path_scores,self.path,self.path)) rc,sout,serr=gromacs.pdb2gmx(f=self.path+"/complex_"+self.pep_chain+".pdb", p=self.path+"/binder.top", o=self.path+"/complex_"+self.pep_chain+".gro", stdout=False, input=('6','6')) os.system("sed -i '/forcefield/d' {}/binder.top".format(self.path)) os.system("sed -i '/\[ system \]/,$d' {}/binder.top".format(self.path)) os.system("mv {}/binder.top {}/complex_Protein_chain_{}.itp".format(self.path,self.path,self.pep_chain)) rc,sout,serr=gromacs.editconf(f=self.path+"/complex_"+self.pep_chain+".gro", o=self.path+"/complex_"+self.pep_chain+".pdb", stdout=False) # Fix the amino acid nomenclature os.system("for i in ASP ARG HIS HIE HID HIP LYS GLU SER THR ASN GLN CYS CYX GLY PRO ALA VAL ILE LEU MET PHE TYR TRP; do sed -i s/\"$i \"/\"$i {}\"/g {}/complex_{}.pdb; done".format(self.pep_chain,self.path,self.pep_chain)) for i,ch in enumerate(self.chain_join): if i==0: os.system("grep ATOM {}/complex_{}.pdb > {}/complex.pdb".format(self.path,ch,self.path)) os.system("echo 'TER' >> {}/complex.pdb".format(self.path)) else: os.system("grep ATOM {}/complex_{}.pdb >> {}/complex.pdb".format(self.path,ch,self.path)) os.system("echo 'TER' >> {}/complex.pdb".format(self.path)) # Get the new complex.pdb and the peptide chain itp file and delete temporal files os.system("grep ATOM {}/complex_{}.pdb >> {}/complex.pdb".format(self.path,self.pep_chain,self.path)) os.system("echo 'TER' >> {}/complex.pdb".format(self.path)) os.system("rm {}/complex_*.pdb".format(self.path)) os.system("rm {}/complex_*.gro".format(self.path)) os.system("rm {}/chains.seq".format(self.path)) os.system("head -n -18 {}/complex_Protein_chain_{}.itp > {}/temp; mv {}/temp {}/complex_Protein_chain_{}.itp".format(self.path,self.pep_chain,self.path,self.path,self.path,self.pep_chain)) # Copy the topol files of the target chains, which are the same always # Copy the topol files of the target chains, which are the same always if self.target=="protein": for ch in self.chain_join: os.system("cp {}/topol_Protein_chain_{}.itp {}/complex_Protein_chain_{}.itp".format(self.path,ch,self.path,ch)) if self.target=="drug": for ch in self.chain_join: os.system("cp {}/topol_Drug_chain_{}.itp {}/complex_Drug_chain_{}.itp".format(self.path,ch,self.path,ch)) # Copy the topol.top to complex.top and delete all the additional atoms os.system("cp {}/topol.top {}/complex.top".format(self.path,self.path)) os.system("sed -i '/Ion/d' {}/complex.top".format(self.path)) os.system("sed -i '/SOL/d' {}/complex.top".format(self.path)) os.system("sed -i '/NA/d' {}/complex.top".format(self.path)) os.system("sed -i '/CL/d' {}/complex.top".format(self.path)) os.system("sed -i '/solvent/d' {}/complex.top".format(self.path)) os.system("sed -i 's/topol_/complex_/g' {}/complex.top".format(self.path)) # Get a pdb of the complex where an index will be created rc,sout,serr=gromacs.make_ndx(f=self.path+"/complex.pdb", o=self.path+"/reference.ndx", stdout=False, input=('q')) ref_ndx = NDX() ref_ndx.read(self.path+"/reference.ndx") #index_ref=len(ref_ndx)-1 bash="grep '\[' {}/reference.ndx | wc -l".format(self.path) number_index = subprocess.check_output(['bash','-c', bash]) index_ref=int(number_index)-1 gromacs.utilities.unlink_gmx(self.path+"/reference.ndx") # Create the side chain index input_for_ndx=() counter=index_ref input_for_ndx+=('chain {}'.format(self.pep_chain),); counter+=1 input_for_ndx+=('name {} binder'.format(counter),); input_for_ndx+=('"SideChain" & "binder"'+' & r {}'.format(self.pep_position),); counter+=1 input_for_ndx+=('"System" &! {}'.format(counter),); counter+=1 input_for_ndx+=('name {} scmut'.format(counter),); sentence="" for i,ch in enumerate(self.chain_join): if i==0: sentence=sentence+"chain {}".format(ch) else: sentence=sentence+" | chain {}".format(ch) input_for_ndx+=(sentence,); counter+=1 input_for_ndx+=('name {} target'.format(counter),) input_for_ndx+=('\"target\" | \"binder\"',); counter+=1 input_for_ndx+=('name {} complex'.format(counter),) input_for_ndx+=('q',) # Generate the index file rc,sout,serr=gromacs.make_ndx(f=self.path+"/complex.pdb", o=self.path+"/scmut.ndx", stdout=False, input=input_for_ndx) # Generate the gro file rc,sout,serr=gromacs.editconf(f=self.path+"/complex.pdb", o=self.path+"/complex.gro", stdout=False) # Add a small box for the residues os.system("sed -i '$ d' {}/complex.gro".format(self.path)) os.system('echo " 20.0 20.0 20.0" >> {path}/complex.gro'.format(path=self.path)) # Prepare the files for the minimization rc,sout,serr=gromacs.grompp(f=self.path+"/mdp/minim_scmut.mdp", o=self.path+"/complex.tpr", p=self.path+"/complex.top", n=self.path+"/scmut.ndx", c=self.path+"/complex.gro", stdout=False) gromacs.utilities.unlink_gmx("mdout.mdp") # Run the minimization of the side chain alone and the residues around it if run_minim: # Run the minimization print("Running first minimization ...") rc,sout,serr=gromacs.mdrun(deffnm=self.path+"/complex", stdout=False) # Get the complex pdb file rc,sout,serr=gromacs.trjconv(f=self.path+"/complex.gro",s=self.path+"/complex.tpr", n=self.path+"/scmut.ndx", o=self.path+"/min_complex.pdb",stdout=False,input=("complex")) os.system("rm posre.itp {path}/complex.tpr {path}/complex.top; grep -v ENDMDL {path}/min_complex.pdb | grep -v MODEL > {path}/complex.pdb; rm {path}/min_complex.pdb {path}/complex.log {path}/complex.trr {path}/complex.edr {path}/scmut.ndx".format(path=self.path))