Files
2026-08-03 18:42:47 +08:00

252 lines
7.1 KiB
Python

'''
(c) 2010-2012 Thomas Holder (https://github.com/speleo3/pymol-psico)
(c) 2016 Thomas Holder, Schrodinger, Inc.
License: BSD-2-Clause
'''
from pymol import cmd, CmdException
def pdb2pqr(name, selection='all', ff='amber', debump=1, opt=1, assignonly=0,
ffout='', ph=None, neutraln=0, neutralc=0, state=-1, preserve=0,
exe='pdb2pqr', quiet=1):
'''
DESCRIPTION
Creates a new molecule object from a selection and adds missing atoms,
assignes charges and radii using PDB2PQR.
http://www.poissonboltzmann.org/pdb2pqr/
USAGE
pdb2pqr name [, selection [, ff [, debump [, opt [, assignonly [, ffout [,
ph [, neutraln [, neutralc [, state [, preserve ]]]]]]]]]]]
ARGUMENTS
name = string: name of object to create or modify
selection = string: atoms to include in the new object {default: all}
ff = string: forcefield {default: amber}
'''
debump, opt, assignonly = int(debump), int(opt), int(assignonly)
neutraln, neutralc = int(neutraln), int(neutralc)
quiet = int(quiet)
args = ['--ff=' + ff, '--chain']
if not debump:
args.append('--nodebump')
if not opt:
args.append('--noopt')
if assignonly:
args.append('--assign-only')
if ffout:
args.append('--ffout=' + ffout)
if ph is not None:
args.append('--with-ph=%f' % float(ph))
if neutraln:
args.append('--neutraln')
if neutralc:
args.append('--neutralc')
if not quiet:
args.append('--verbose')
r = pdb2pqr_cli(name, selection, args, state, preserve, exe, quiet)
if not quiet:
if r:
print(r)
print(' pdb2pqr: done')
return r
def pdb2pqr_cli(name, selection, options, state=-1, preserve=0,
exe='pdb2pqr', quiet=1, fixrna=0, _proclist=None):
import os, tempfile, subprocess, shutil
state, preserve, quiet = int(state), int(preserve), int(quiet)
if cmd.is_string(options):
import shlex
options = shlex.split(options)
args = [cmd.exp_path(exe)] + list(options)
tmpdir = tempfile.mkdtemp()
# Input format should be PDB, but use PQR instead because we can support
# multi-state assemblies by not writing MODEL records.
infile = os.path.join(tmpdir, 'in.pqr')
outfile = os.path.join(tmpdir, 'out.pqr')
args.extend([infile, outfile])
# For some reason, catching stdout/stderr with PIPE and communicate()
# blocks terminate() calls from terminating early. Using a file
# redirect doesn't show this problem.
f_stdout = open(os.path.join(tmpdir, 'stdout.txt'), 'w+')
# RNA resdiue names must be RA, RC, RG, and RU
tmpmodel = ''
if int(fixrna) and cmd.count_atoms('(%s) & resn A+C+G+U' % (selection)):
tmpmodel = cmd.get_unused_name('_tmp')
cmd.create(tmpmodel, selection, zoom=0)
cmd.alter(tmpmodel + ' & polymer.nucleic & resn A+C+G+U',
'resn = "R" + resn')
selection = tmpmodel
try:
cmd.save(infile, selection, state)
p = subprocess.Popen(args, cwd=tmpdir,
stdin=subprocess.PIPE, # Windows pythonw fix
stdout=f_stdout,
stderr=f_stdout)
p.stdin.close() # Windows pythonw fix
if _proclist is not None:
_proclist.append(p)
p.wait()
# This allows PyMOL to capture it and display the output in the GUI.
f_stdout.seek(0)
print(f_stdout.read().rstrip())
if p.returncode == -15: # SIGTERM
raise CmdException('pdb2pqr terminated')
if p.returncode != 0:
raise CmdException('%s failed with exit status %d' %
(args[0], p.returncode))
warnings = [L[10:] for L in open(outfile) if L.startswith('REMARK 5')]
warnings = ''.join(warnings).strip()
cmd.load(outfile, name)
return warnings
except OSError as e:
print(e)
raise CmdException('Cannot execute "%s"' % (exe))
finally:
if tmpmodel:
cmd.delete(tmpmodel)
f_stdout.close()
if not preserve:
shutil.rmtree(tmpdir)
elif not quiet:
print(' Notice: not deleting', tmpdir)
def _is_exe(exe):
import os, sys
if os.path.exists(exe):
return True
if sys.platform.startswith('win'):
return os.path.exists(exe + '.exe')
return False
def prepwizard(name, selection='all', options='', state=-1,
preserve=0, exe='$SCHRODINGER/utilities/prepwizard', quiet=1,
_proclist=None):
'''
DESCRIPTION
Run the SCHRODINGER Protein Preparation Wizard. Builds missing side
chains and converts MSE to MET. Other non-default options need to be
passed with the "options=" argument.
USAGE
prepwizard name [, selection [, options [, state ]]]
ARGUMENTS
name = str: name of object to create
selection = str: atoms to send to the wizard {default: all}
options = str: additional command line options for prepwizard
state = int: object state {default: -1 (current)}
'''
import os, tempfile, subprocess, shutil, shlex
state, preserve, quiet = int(state), int(preserve), int(quiet)
exe = cmd.exp_path(exe)
if not _is_exe(exe):
if 'SCHRODINGER' not in os.environ:
print(' Warning: SCHRODINGER environment variable not set')
raise CmdException('no such script: ' + exe)
args = [exe, '-mse', '-fillsidechains', '-WAIT']
if options:
if cmd.is_string(options):
options = shlex.split(options)
args.extend(options)
tmpdir = tempfile.mkdtemp()
infile = 'in.pdb'
outfile = 'out.mae'
args.extend([infile, outfile])
try:
cmd.save(os.path.join(tmpdir, infile), selection, state)
env = dict(os.environ)
env.pop('PYTHONEXECUTABLE', '') # messes up Python on Mac
import pymol
if pymol.IS_WINDOWS:
# Fix for 2020-4 (PYMOL-3572)
import ctypes
ctypes.windll.kernel32.SetDllDirectoryW(None)
p = subprocess.Popen(args, cwd=tmpdir,
env=env,
universal_newlines=True,
stdin=subprocess.PIPE, # Windows pythonw fix
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
if _proclist is not None:
_proclist.append(p)
print(p.communicate()[0].rstrip())
if p.wait() == -15: # SIGTERM
raise CmdException('prepwizard terminated')
if p.returncode != 0:
raise CmdException('%s failed with exit status %d' % (args[0], p.returncode))
cmd.load(os.path.join(tmpdir, outfile), name)
except OSError as e:
print(e)
raise CmdException('Cannot execute "%s"' % (exe))
finally:
logfile = os.path.join(tmpdir, 'in.log')
if os.path.exists(logfile):
with open(logfile) as handle:
print(handle.read())
if not preserve:
shutil.rmtree(tmpdir)
elif not quiet:
print(' Notice: not deleting', tmpdir)
if not quiet:
print(' prepwizard: done')
# vi: ts=4:sw=4:smarttab:expandtab