Files
PlantAI-dev/tools/pymol-open-source/data/startup/apbs_gui/electrostatics.py
T
2026-08-03 18:42:47 +08:00

196 lines
5.2 KiB
Python

'''
APBS wrapper
(c) 2012 Thomas Holder (https://github.com/speleo3/pymol-psico)
(c) 2016 Thomas Holder, Schrodinger, Inc.
License: BSD-2-Clause
'''
import os
from pymol import cmd, CmdException
template_apbs_in = '''
read
mol pqr "{pqrfile}"
end
elec
mg-auto
mol 1
fgcent {fgcent} # fine grid center
cgcent mol 1 # coarse grid center
fglen {fglen}
cglen {cglen}
dime {dime}
lpbe # l=linear, n=non-linear Poisson-Boltzmann equation
bcfl sdh # "Single Debye-Hueckel" boundary condition
pdie 2.0 # protein dielectric
sdie 78.0 # solvent dielectric
chgm spl2 # Cubic B-spline discretization of point charges on grid
srfm smol # smoothed surface for dielectric and ion-accessibility coefficients
swin 0.3
temp 310.0 # temperature
sdens 10.0
calcenergy no
calcforce no
srad {srad} # solvent radius
ion charge +1 conc 0.15 radius 2.0
ion charge -1 conc 0.15 radius 1.8
write pot dx "{mapfile}"
end
quit
'''
def find_apbs_exe():
import shutil
exe = shutil.which('apbs')
if not exe:
exe = cmd.exp_path('$SCHRODINGER/utilities/apbs')
if not os.path.exists(exe):
return None
return exe
def validate_apbs_exe(exe):
'''Get and validate apbs executable.
Raise CmdException if not found or broken.'''
import subprocess
if exe:
exe = cmd.exp_path(exe)
else:
exe = find_apbs_exe() or 'apbs'
try:
r = subprocess.call([exe, "--version"],
stdin=subprocess.PIPE, # Windows pythonw fix
stdout=open(os.devnull, "w"), stderr=subprocess.STDOUT)
if r < 0:
raise CmdException("Broken executable: " + exe)
except OSError as e:
print(e)
raise CmdException("Cannot execute: " + exe)
return exe
def map_new_apbs(name, selection='all', grid=0.5, buffer=10.0, state=1,
preserve=0, exe='', assign=0, focus='', quiet=1, _template='',
_proclist=None):
'''
DESCRIPTION
Create electrostatic potential map with APBS.
"selection" needs partial charges (partial_charge) and radii (elec_radius)
assigned. These can be loaded for example from a PQR file.
SEE ALSO
map_new (coulomb), psico.electrostatics
'''
import tempfile, shutil, glob, subprocess
selection = '(%s) and not solvent' % (selection)
grid, buffer, state = float(grid), float(buffer), int(state)
preserve, assign, quiet = int(preserve), int(assign), int(quiet)
# path to apbs executable
exe = validate_apbs_exe(exe)
# temporary directory
tempdir = tempfile.mkdtemp()
if not quiet:
print(' Tempdir:', tempdir)
# filenames
pqrfile = os.path.join(tempdir, 'mol.pqr')
infile = os.path.join(tempdir, 'apbs.in')
stem = os.path.join(tempdir, 'map')
# temporary selection
tmpname = cmd.get_unused_name('_sele')
cmd.select(tmpname, selection, 0)
cmd.save(pqrfile, tmpname, state, format='pqr', quiet=quiet)
# grid dimensions
extent = cmd.get_extent(tmpname, state)
extentfocus = cmd.get_extent(focus) if focus else extent
fglen = [(emax-emin + 2*buffer) for (emin, emax) in zip(*extentfocus)]
cglen = [(emax-emin + 4*buffer) for (emin, emax) in zip(*extent)]
# make coarse grid a cube (better for non-globular shapes)
cglen = [max(cglen)] * 3
cmd.delete(tmpname)
apbs_in = {
'pqrfile': pqrfile,
'fgcent': 'mol 1',
'fglen': '%f %f %f' % tuple(fglen),
'cglen': '%f %f %f' % tuple(cglen),
'srad': cmd.get('solvent_radius'),
'mapfile': stem,
}
if focus:
apbs_in['fgcent'] = '%f %f %f' % tuple((emax + emin) / 2.0
for (emin, emax) in zip(*extentfocus))
try:
# apbs will fail if grid does not fit into memory
# -> on failure repeat with larger grid spacing
for _ in range(3):
dime = [1 + max(64, n / grid) for n in fglen]
apbs_in['dime'] = '%d %d %d' % tuple(dime)
# apbs input file
with open(infile, 'w') as f:
f.write((_template or template_apbs_in).format(**apbs_in))
# run apbs
p = subprocess.Popen([exe, infile], cwd=tempdir)
if _proclist is not None:
_proclist.append(p)
r = p.wait()
if r == -15: # SIGTERM
raise CmdException('apbs terminated')
if r == 0:
break
if r in (-6, -9):
grid *= 2.0
if not quiet:
print(' Warning: retry with grid =', grid)
continue
raise CmdException('apbs failed with code ' + str(r))
dx_list = glob.glob(stem + '*.dx')
if not dx_list:
dx_list = glob.glob(stem + '*.dxbin')
if len(dx_list) != 1:
raise CmdException('dx file missing')
# load map
cmd.load(dx_list[0], name, quiet=quiet)
except OSError as e:
print(e)
raise CmdException('Cannot execute "%s"' % (exe))
finally:
if not preserve:
shutil.rmtree(tempdir)
elif not quiet:
print(' Notice: not deleting %s' % (tempdir))
# vi: ts=4:sw=4:smarttab:expandtab