|
|
Line 24: |
Line 24: |
| There are two ways to get the new plugin | | There are two ways to get the new plugin |
|
| |
|
| * If you have subversion installed, | | * If you have subversion installed, you can always get the latest version via |
|
| |
|
| <source lang="bash"> | | <source lang="bash"> |
Line 30: |
Line 30: |
| </source> | | </source> |
|
| |
|
| * Copy the text directly from http://pymolwiki.org/index.php/User:Mglerner and put it in a file called apbsplugin.py | | * You can download the zip file from http://pymolwiki.org/index.php/User:Mglerner . Upon unzipping it, you should have a file called apbsplugin.py |
|
| |
|
| Once you have the plugin, you can install it via PyMOL's plugin installer: Plugin --> Manage Plugins --> Install | | Once you have the plugin, you can install it via PyMOL's plugin installer: Plugin --> Manage Plugins --> Install |
Line 47: |
Line 47: |
| * Gives better diagnostic information so that PyMOL/APBS developers can find bugs more easily | | * Gives better diagnostic information so that PyMOL/APBS developers can find bugs more easily |
| * Lots of internal code cleanup | | * Lots of internal code cleanup |
|
| |
| == Plugin code ==
| |
|
| |
| <source lang="python">
| |
| #!/usr/bin/env python
| |
|
| |
| # TODO:
| |
| # - provide diff for pdb2pqr freemol
| |
| # - use remove_alt to count alternate atom locations and warn the user
| |
| #
| |
| # - Note to users that they should remove freemol's pymol.exe on OS X.
| |
|
| |
| ### (all) and resn glu and resi 154+157
| |
| ### flag ignore, atom-selection, clear
| |
|
| |
| # APBS TOOLS Copyright Notice
| |
| # ============================
| |
| #
| |
| # The APBS TOOLS source code is copyrighted, but you can freely use and
| |
| # copy it as long as you don't change or remove any of the copyright
| |
| # notices.
| |
| #
| |
| # ----------------------------------------------------------------------
| |
| # APBS TOOLS is Copyright (C) 2009 by Michael G. Lerner
| |
| #
| |
| # All Rights Reserved
| |
| #
| |
| # Permission to use, copy, modify, distribute, and distribute modified
| |
| # versions of this software and its documentation for any purpose and
| |
| # without fee is hereby granted, provided that the above copyright
| |
| # notice appear in all copies and that both the copyright notice and
| |
| # this permission notice appear in supporting documentation, and that
| |
| # the name of Michael G. Lerner not be used in advertising or publicity
| |
| # pertaining to distribution of the software without specific, written
| |
| # prior permission.
| |
| #
| |
| # MICHAEL G. LERNER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
| |
| # SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
| |
| # FITNESS. IN NO EVENT SHALL MICHAEL G. LERNER BE LIABLE FOR ANY
| |
| # SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
| |
| # RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
| |
| # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
| |
| # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
| |
| # ----------------------------------------------------------------------
| |
|
| |
| """
| |
|
| |
| A NOTE TO USERS:
| |
|
| |
| You can change the default locations for the APBS and PDB2PQR binaries
| |
| as well as the default temporary file directory below. If you set them
| |
| in this file, they will be preserved each time you load up the
| |
| plugin. Scroll down to the section entitled "Global config variables"
| |
| (no quotes) below.
| |
|
| |
| A NOTE TO OTHER DEVELOPERS:
| |
|
| |
| I understand that I'm giving this code away for Free, and that there's
| |
| not a ton of great sample PyMOL plugin code out there, so you're
| |
| certainly encouraged to use this as a template. However, please
| |
| acknowledge me in some way if you do (somewhere in the comments if you
| |
| only use a little bit of code or something more if you use a lot).
| |
|
| |
| Thanks.
| |
|
| |
| -Michael
| |
|
| |
| Features under consideration:
| |
|
| |
| - Use 'acc' to calculate solvent-accessible surface areas. We'll use
| |
| the PyMOL 'standard' method and store this data as B-factors.
| |
| - Show the field lines. Relevant code from menu.py:
| |
|
| |
| def map_gradient(self_cmd, sele):
| |
| return [[ 2, 'Gradient:', '' ],
| |
| [ 1, 'default' , 'cmd.gradient("'+sele+'_grad","'+sele+'");cmd.ramp_new("'+sele+
| |
| '_grad_ramp","'+sele+'");cmd.color("'+sele+'_grad_ramp","'+sele+'_grad");' ]
| |
| ]
| |
|
| |
| Known hacks:
| |
|
| |
|
| |
| 1. (code in execute() )There's a bug in the version of APBS shipped
| |
| with Ubuntu 9.10 (version 1.1.0) that causes the name to become
| |
| foo-PE0.dx instead of foo.dx. This would normally only occur in
| |
| mg-para calcs or MPI versions of apbs. It's clearly bug-possible,
| |
| but we will check for foo-PE0 if we can't find foo.dx.
| |
|
| |
| 2. We look for dylib errors in the APBS executable that's shipped with
| |
| freemol on OS X. Code in get_default()'s verify().
| |
|
| |
| """
| |
| from __future__ import division
| |
| from __future__ import generators
| |
|
| |
| global DEBUG
| |
| DEBUG = 1
| |
|
| |
| APBS_DEFAULT=True
| |
|
| |
| import os,math,re
| |
| import string
| |
| import Tkinter
| |
| from Tkinter import *
| |
| import Pmw
| |
| import distutils.spawn # used for find_executable
| |
| import traceback
| |
| import pymol
| |
|
| |
| #
| |
| # Global config variables
| |
| #
| |
| # To change the default locations, change these to something like
| |
| # APBS_BINARY_LOCATION = '/opt/bin/apbs'
| |
| #
| |
| APBS_BINARY_LOCATION = None
| |
| APBS_PSIZE_LOCATION = None
| |
| APBS_PDB2PQR_LOCATION = None
| |
| TEMPORARY_FILE_DIR = None
| |
|
| |
| apbs_plea = ("IMPORTANT REQUEST: If you have not already done so, please register\n"
| |
| "your use of the open-source Adaptive Poisson-Boltzmann Solver (APBS) at\n"
| |
| "-> http://agave.wustl.edu/apbs/download\n"
| |
| "Such proof of usage is vital in securing funding for APBS development!\n")
| |
|
| |
| pdb2pqr_plea = ("IMPORTANT REQUEST: If you have not already done so, please register\n"
| |
| "your use of the open-source PDB2PQR at\n"
| |
| "-> http://www.poissonboltzmann.org/pdb2pqr/d\n"
| |
| "Such proof of usage is vital in securing funding for PDB2PQR development!\n")
| |
| global apbs_message, pdb2pqr_message
| |
| apbs_message = """You must have APBS installed on your system."""
| |
| pdb2pqr_message = """PDB2PQR can be used to generate .PQR files."""
| |
|
| |
| def get_default_location(name):
| |
| """
| |
| Given the name of an APBS-related binary, look in
| |
| * pymol path,
| |
| * freemol path,
| |
| * user defined places,
| |
| * the system path,
| |
| * Known other paths (/usr/local/bin and /opt/local/bin)
| |
| for the parameter, name.
| |
|
| |
| Some programs are verified with additional tests. In particular,
| |
| some versions of PyMOL ship with a broken apbs.exe, so we verify
| |
| that it can be run.
| |
|
| |
| PARAMS
| |
| name, (string) the basename of the file we're looking for
| |
| EXAMPLE
| |
| get_default_location("apbs.exe")
| |
| RETURNS
| |
| (string) path/to/file on success or "" on failure
| |
| NOTES
| |
| For any program name <foo>.exe we will also search for
| |
| <foo>. We'll search for the .exe version first. We do not
| |
| automatically check for .exe versions of programs when .exe is
| |
| not specified.
| |
| """
| |
| def verify(name,f):
| |
| if name in 'apbs.exe apbs'.split():
| |
| # You'd think we could just check the return code, but
| |
| # APBS doesn't return zero on success. Instead, it returns
| |
| # things like 3328. It seems to return 5 or -5 in this
| |
| # particular failure case, but I'm not sure we can depend
| |
| # on that always.
| |
| (retcode,prog_out) = run(f,'--version')
| |
| if 'dyld: Library not loaded' in prog_out:
| |
| print "Skipping",f,"because it appears to be broken (dyld)"
| |
| return False
| |
| return True
| |
| searchDirs = []
| |
| if "FREEMOL" in os.environ:
| |
| searchDirs.append(os.environ["FREEMOL"])
| |
| if "PYMOL_PATH" in os.environ:
| |
| searchDirs.append(os.path.join(os.environ["PYMOL_PATH"], "ext", "bin"))
| |
| searchDirs.append(os.path.join(os.environ["PYMOL_PATH"], "freemol", "bin"))
| |
| searchDirs.append(os.path.join(os.environ["PYMOL_PATH"], "freemol", "share", "apbs"))
| |
| searchDirs.append(os.path.join(os.environ["PYMOL_PATH"], "freemol", "share", "pdb2pqr"))
| |
| for x in (APBS_BINARY_LOCATION, APBS_PSIZE_LOCATION, APBS_PDB2PQR_LOCATION):
| |
| if x != None and x != "":
| |
| searchDirs.append(x)
| |
| if name=="temp":
| |
| searchDirs = []
| |
| if TEMPORARY_FILE_DIR != None and TEMPORARY_FILE_DIR != "":
| |
| searchDirs.append(TEMPORARY_FILE_DIR)
| |
| searchDirs.append("/tmp")
| |
| searchDirs.append(".")
| |
|
| |
| searchDirs.extend(string.split(os.environ["PATH"], ":"))
| |
| searchDirs.append(os.path.join("/usr", "local", "bin"))
| |
| searchDirs.append(os.path.join("/opt", "local", "bin"))
| |
|
| |
| print "Search dirs",searchDirs
| |
|
| |
| if DEBUG:
| |
| print "get_default_location will search the following: ", searchDirs
| |
| for d in searchDirs:
| |
| if name=="temp":
| |
| f = d # just search for the directory
| |
| else:
| |
| f = os.path.join( d, name ) # make path/name.py
| |
| print "trying",f
| |
| if os.path.exists(f) and verify(name,f):
| |
| return f
| |
| elif name.endswith('.exe'):
| |
| f = os.path.join( d, name[:-4] ) # make path/name.py
| |
| if os.path.exists(f) and verify(name,f):
| |
| return f
| |
|
| |
| print "Could not find default location for file: %s" % name
| |
| return ""
| |
|
| |
| def __init__(self):
| |
| """
| |
| Init PyMOL, by adding APBSTools to the GUI under Plugins
| |
|
| |
| Creates the APBS widget/notebook. Once the event is received,
| |
| we create a new instance of APBSTools2 which is a Pmw, which upon
| |
| creation shows itself.
| |
| """
| |
| self.menuBar.addmenuitem('Plugin', 'command',
| |
| 'Launch APBS Tools2',
| |
| label='APBS Tools2...',
| |
| command = lambda s=self: APBSTools2(s))
| |
|
| |
| def run(prog,args):
| |
| '''
| |
| wrapper to handle spaces on windows.
| |
| prog is the full path to the program.
| |
| args is a string that we will split up for you.
| |
| or a tuple. or a list. your call.
| |
|
| |
| return value is (retval,prog_out)
| |
|
| |
| e.g.
| |
|
| |
| (retval,prog_out) = run("/bin/ls","-al /tmp/myusername")
| |
| '''
| |
| import subprocess,tempfile
| |
|
| |
| if type(args) == type(''):
| |
| args = tuple(args.split())
| |
| elif type(args) in (type([]),type(())):
| |
| args = tuple(args)
| |
| args = (prog,) + args
| |
|
| |
| try:
| |
| output_file = tempfile.TemporaryFile(mode="w+") # <-- shouldn't this point to the temp dir
| |
| except IOError:
| |
| print "Error opening output_file when trying to run the APBS command."
| |
|
| |
| print "Running",args
| |
| retcode = subprocess.call(args,stdout=output_file.fileno(),stderr=subprocess.STDOUT)
| |
| output_file.seek(0)
| |
| #prog_out = output_file.read()
| |
| prog_out = ''.join(output_file.readlines())
| |
| output_file.close() #windows doesn't do this automatically
| |
| if DEBUG:
| |
| print "Results were:"
| |
| print "Return value:",retcode
| |
| print "Output:"
| |
| print prog_out
| |
| return (retcode,prog_out)
| |
|
| |
| class util:
| |
| """
| |
| A quick collection of utility functions.
| |
| """
| |
| #@staticmethod
| |
| def getMolecules():
| |
| """returns all molecules that PyMOL knows about"""
| |
| return [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:molecule']
| |
| getMolecules = staticmethod(getMolecules)
| |
| #@staticmethod
| |
| def getMaps():
| |
| """returns all maps that PyMOL knows about"""
| |
| return [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:map']
| |
| getMaps = staticmethod(getMaps)
| |
| #def hasAlt(sel):
| |
| # """returns true if non-standard locations (rotamers) are present for this selection"""
| |
| # return cmd.count_atoms(sel + " and not alt ''")!=0
| |
| #hasAlt = staticmethod(hasAlt)
| |
|
| |
| util = util()
| |
|
| |
| ##############################################################################
| |
| ##############################################################################
| |
| ### ###
| |
| ### ApbsInterface ###
| |
| ### ###
| |
| ##############################################################################
| |
| ##############################################################################
| |
|
| |
| def getApbsInputFile(pqr_filename,
| |
| grid_points,
| |
| cglen,
| |
| fglen,
| |
| cent,
| |
| apbs_mode,
| |
| bcfl,
| |
| ion_plus_one_conc,ion_plus_one_rad,
| |
| ion_minus_one_conc,ion_minus_one_rad,
| |
| ion_plus_two_conc,ion_plus_two_rad,
| |
| ion_minus_two_conc,ion_minus_two_rad,
| |
| interior_dielectric, solvent_dielectric,
| |
| chgm,
| |
| srfm,
| |
| solvent_radius,
| |
| system_temp,
| |
| sdens,
| |
| dx_filename,
| |
| ):
| |
| print "Getting APBS input"
| |
| #print "system_temp",system_temp,type(system_temp)
| |
| #print "sdens",sdens,type(sdens)
| |
| #
| |
| # How shall we set up the grid? We'll use cglen, fglen, cgcent, fgcent
| |
| # and dime.
| |
| # This allows people to automate things (e.g. "Alanine scanning")
| |
| #
| |
|
| |
| #
| |
| # New template using mg-auto
| |
| # See http://agave.wustl.edu/apbs/doc/api/html/#mg-auto
| |
| #
| |
|
| |
| apbs_template = """#
| |
| # Note that most of the comments here were taken from sample
| |
| # input files that came with APBS. You can find APBS at
| |
| # http://agave.wustl.edu/apbs/
| |
| # Note that APBS is GPL'd code.
| |
| #
| |
| read
| |
| mol pqr %s # read molecule 1
| |
| end
| |
| elec
| |
| mg-auto
| |
| dime %d %d %d # number of find grid points
| |
| # calculated by psize.py
| |
| cglen %f %f %f # coarse mesh lengths (A)
| |
| fglen %f %f %f # fine mesh lengths (A)
| |
| # calculated by psize.py
| |
| cgcent %f %f %f # (could also give (x,y,z) form psize.py) #known center
| |
| fgcent %f %f %f # (could also give (x,y,z) form psize.py) #known center
| |
| %s # solve the full nonlinear PBE with npbe
| |
| #lpbe # solve the linear PBE with lpbe
| |
| bcfl %s # Boundary condition flag
| |
| # 0 => Zero
| |
| # 1 => Single DH sphere
| |
| # 2 => Multiple DH spheres
| |
| # 4 => Focusing
| |
| #
| |
| #ion 1 0.000 2.0 # Counterion declaration:
| |
| ion charge 1 conc %f radius %f # Counterion declaration:
| |
| ion charge -1 conc %f radius %f # ion <charge> <conc (M)> <radius>
| |
| ion charge 2 conc %f radius %f # ion <charge> <conc (M)> <radius>
| |
| ion charge -2 conc %f radius %f # ion <charge> <conc (M)> <radius>
| |
| pdie %f # Solute dielectric
| |
| sdie %f # Solvent dielectric
| |
| chgm %s # Charge disc method
| |
| # 0 is linear splines
| |
| # 1 is cubic b-splines
| |
| mol 1 # which molecule to use
| |
| srfm smol # Surface calculation method
| |
| # 0 => Mol surface for epsilon;
| |
| # inflated VdW for kappa; no
| |
| # smoothing
| |
| # 1 => As 0 with harmoinc average
| |
| # smoothing
| |
| # 2 => Cubic spline
| |
| srad %f # Solvent radius (1.4 for water)
| |
| swin 0.3 # Surface cubic spline window .. default 0.3
| |
| temp %f # System temperature (298.15 default)
| |
| sdens %f # Specify the number of grid points per square-angstrom to use in Vacc object. Ignored when srad is 0.0 (see srad) or srfm is spl2 (see srfm). There is a direct correlation between the value used for the Vacc sphere density, the accuracy of the Vacc object, and the APBS calculation time. APBS default value is 10.0.
| |
| #gamma 0.105 # Surface tension parameter for apolar forces (in kJ/mol/A^2)
| |
| # only used for force calculations, so we don't care, but
| |
| # it *used to be* always required, and 0.105 is the default
| |
| calcenergy no # Energy I/O to stdout
| |
| # 0 => don't write out energy
| |
| # 1 => write out total energy
| |
| # 2 => write out total energy and all
| |
| # components
| |
| calcforce no # Atomic forces I/O (to stdout)
| |
| # 0 => don't write out forces
| |
| # 1 => write out net forces on molecule
| |
| # 2 => write out atom-level forces
| |
| write pot dx %s # What to write .. this says write the potential in dx
| |
| # format to a file.
| |
| end
| |
| quit
| |
|
| |
| """
| |
| return apbs_template % (pqr_filename,
| |
| grid_points[0], grid_points[1], grid_points[2],
| |
| cglen[0],cglen[1],cglen[2],
| |
| fglen[0],fglen[1],fglen[2],
| |
| cent[0],cent[1],cent[2],
| |
| cent[0],cent[1],cent[2],
| |
| apbs_mode,
| |
| bcfl,
| |
| ion_plus_one_conc,ion_plus_one_rad,
| |
| ion_minus_one_conc,ion_minus_one_rad,
| |
| ion_plus_two_conc,ion_plus_two_rad,
| |
| ion_minus_two_conc,ion_minus_two_rad,
| |
| interior_dielectric, solvent_dielectric,
| |
| chgm,
| |
| solvent_radius,
| |
| system_temp,
| |
| sdens,
| |
| dx_filename,
| |
| )
| |
|
| |
|
| |
|
| |
| ##############################################################################
| |
| ##############################################################################
| |
| ### ###
| |
| ### PluginCode ###
| |
| ### ###
| |
| ##############################################################################
| |
| ##############################################################################
| |
|
| |
|
| |
|
| |
| class APBSTools2:
| |
| # The current goal is to factor all of the APBS-specific code into
| |
| # an ApbsInterface class. The functions defined here before
| |
| # __init__, as well as the functions defined on the various
| |
| # Panels/Panes, will call through to self.ApbsInterface.
| |
| def setPqrFile(self,name):
| |
| print " APBS Tools: set pqr file to",name
| |
| self.pqr_to_use.setvalue(name)
| |
| self.radiobuttons.setvalue('Use another PQR')
| |
| def getPqrFilename(self):
| |
| if self.radiobuttons.getvalue() != 'Use another PQR':
| |
| return self.pymol_generated_pqr_filename.getvalue()
| |
| else:
| |
| return self.pqr_to_use.getvalue()
| |
| def setPsizeLocation(self,value):
| |
| self.psize.setvalue(value)
| |
| def setBinaryLocation(self,value):
| |
| self.binary.setvalue(value)
| |
| def setPdb2pqrLocation(self,value):
| |
| self.pdb2pqr.setvalue(value)
| |
|
| |
| def setPymolGeneratedPqrFilename(self,value):
| |
| self.pymol_generated_pqr_filename.setvalue(value)
| |
| def setPymolGeneratedPdbFilename(self,value):
| |
| self.pymol_generated_pdb_filename.setvalue(value)
| |
| def setPymolGeneratedDxFilename(self,value):
| |
| self.pymol_generated_dx_filename.setvalue(value)
| |
| def setPymolGeneratedInFilename(self,value):
| |
| self.pymol_generated_in_filename.setvalue(value)
| |
|
| |
|
| |
| def getPymolGeneratedPqrFilename(self):
| |
| return self.pymol_generated_pqr_filename.getvalue()
| |
| def getPymolGeneratedPdbFilename(self):
| |
| return self.pymol_generated_pdb_filename.getvalue()
| |
| def getPymolGeneratedDxFilename(self):
| |
| return self.pymol_generated_dx_filename.getvalue()
| |
| def getPymolGeneratedInFilename(self):
| |
| return self.pymol_generated_in_filename.getvalue()
| |
| defaults = {
| |
| "interior_dielectric" : 2.0,
| |
| "solvent_dielectric" : 78.0,
| |
| "solvent_radius" : 1.4,
| |
| "system_temp" : 310.0,
| |
| "apbs_mode" : 'Linearized Poisson-Boltzmann Equation',
| |
| "ion_plus_one_conc" : 0.15,
| |
| "ion_plus_one_rad" : 2.0,
| |
| "ion_plus_two_conc" : 0.0,
| |
| "ion_plus_two_rad" : 2.0,
| |
| "ion_minus_one_conc" : 0.15,
| |
| "ion_minus_one_rad" : 1.8,
| |
| "ion_minus_two_conc" : 0.0,
| |
| "ion_minus_two_rad" : 2.0,
| |
| #"max_mem_allowed" : 400,
| |
| "max_mem_allowed" : 1500,
| |
| "potential_at_sas" : 0,
| |
| "surface_solvent" : 1,
| |
| "show_surface_for_scanning" : 1,
| |
| #"grid_buffer" : 0,
| |
| #"grid_buffer" : 20,
| |
| "bcfl" : 'Single DH sphere', # Boundary condition flag for APBS
| |
| "sdens": 10.0, # Specify the number of grid points per
| |
| # square-angstrom to use in Vacc
| |
| # object. Ignored when srad is 0.0 (see srad)
| |
| # or srfm is spl2 (see srfm). There is a direct
| |
| # correlation between the value used for the
| |
| # Vacc sphere density, the accuracy of the Vacc
| |
| # object, and the APBS calculation time. APBS
| |
| # default value is 10.0.
| |
| "chgm" : 'Cubic B-splines', # Charge disc method for APBS
| |
| }
| |
|
| |
| def __init__(self,app):
| |
| self.parent = app.root
| |
|
| |
| # Create the dialog.
| |
| self.dialog = Pmw.Dialog(self.parent,
| |
| buttons = ('Register APBS Use', 'Register PDB2PQR Use', 'Set grid', 'Run APBS', 'Exit APBS tools'),
| |
| title = 'PyMOL APBS Tools',
| |
| command = self.execute)
| |
| self.dialog.withdraw()
| |
| Pmw.setbusycursorattributes(self.dialog.component('hull'))
| |
|
| |
| w = Tkinter.Label(self.dialog.interior(),
| |
| text = 'PyMOL APBS Tools\nMichael G. Lerner, Heather A. Carlson, 2009 - http://pymolwiki.org/index.php/APBS\n(incorporates modifications by Warren L. DeLano)',
| |
| background = 'black',
| |
| foreground = 'white',
| |
| #pady = 20,
| |
| )
| |
| w.pack(expand = 1, fill = 'both', padx = 4, pady = 4)
| |
|
| |
| self.notebook = Pmw.NoteBook(self.dialog.interior())
| |
| self.notebook.pack(fill='both',expand=1,padx=10,pady=10)
| |
|
| |
| # Set up the Main page
| |
| page = self.notebook.add('Main')
| |
| group = Pmw.Group(page,tag_text='Main options')
| |
| group.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
| self.selection = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Selection to use: ',
| |
| value='(polymer)',
| |
| )
| |
| self.map = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='What to call the resulting map: ',
| |
| value='apbs_map',
| |
| )
| |
| self.radiobuttons = Pmw.RadioSelect(group.interior(),
| |
| buttontype = 'radiobutton',
| |
| orient = 'vertical',
| |
| labelpos = 'w',
| |
| )
| |
| for text in ('Use PyMOL generated PQR and existing Hydrogens and termini',
| |
| 'Use PyMOL generated PQR and PyMOL generated Hydrogens and termini',
| |
| 'Use another PQR',
| |
| 'Use PDB2PQR',):
| |
| self.radiobuttons.add(text)
| |
| self.radiobuttons.setvalue('Use PyMOL generated PQR and PyMOL generated Hydrogens and termini')
| |
|
| |
| self.pdb2pqr_options = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='pdb2pqr command line options: ',
| |
| value='--ff=AMBER',
| |
| )
| |
| self.pqr_to_use = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setPqrFile,'*.pqr'),
| |
| label_text='\tChoose Externally Generated PQR:',
| |
| )
| |
|
| |
|
| |
|
| |
| for entry in (self.selection,self.map,self.radiobuttons,self.pdb2pqr_options,self.pqr_to_use):
| |
| #for entry in (self.selection,self.map,self.radiobuttons,):
| |
| entry.pack(fill='x',padx=4,pady=1) # vertical
| |
|
| |
|
| |
| # Set up the main "Calculation" page
| |
| page = self.notebook.add('Configuration')
| |
|
| |
| group = Pmw.Group(page,tag_text='Dielectric Constants')
| |
| group.pack(fill = 'both', expand = 1, padx = 4, pady = 5)
| |
| group.grid(column=0, row=0)
| |
| self.interior_dielectric = Pmw.EntryField(group.interior(),labelpos='w',
| |
| label_text = 'Protein Dielectric:',
| |
| value = str(APBSTools2.defaults['interior_dielectric']),
| |
| validate = {'validator' : 'real',
| |
| 'min':0,}
| |
| )
| |
| self.solvent_dielectric = Pmw.EntryField(group.interior(),labelpos='w',
| |
| label_text = 'Solvent Dielectric:',
| |
| value = str(APBSTools2.defaults['solvent_dielectric']),
| |
| validate = {'validator' : 'real',
| |
| 'min':0,}
| |
| )
| |
| entries = (self.interior_dielectric,self.solvent_dielectric)
| |
| for entry in entries:
| |
| #entry.pack(side='left',fill='both',expand=1,padx=4) # side-by-side
| |
| entry.pack(fill='x',expand=1,padx=4,pady=1) # vertical
| |
| group = Pmw.Group(page,tag_text='Other')
| |
| group.pack(fill='both',expand=1, padx=4, pady=5)
| |
| group.grid(column=1, row=1,columnspan=4)
| |
| self.max_mem_allowed = Pmw.EntryField(group.interior(),labelpos='w',
| |
| label_text = 'Maximum Memory Allowed (MB):',
| |
| value = str(APBSTools2.defaults['max_mem_allowed']),
| |
| validate = {'validator' : 'real',
| |
| 'min':1,}
| |
| )
| |
| self.apbs_mode = Pmw.OptionMenu(group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'APBS Mode',
| |
| items = ('Nonlinear Poisson-Boltzmann Equation','Linearized Poisson-Boltzmann Equation',),
| |
| initialitem = APBSTools2.defaults['apbs_mode'],
| |
| )
| |
| self.apbs_mode.pack(fill='x',expand=1,padx=4)
| |
| #self.apbs_mode.grid(column=0,row=0,columnspan=3)
| |
| self.solvent_radius = Pmw.EntryField(group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Solvent Radius:',
| |
| validate = {'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['solvent_radius']),
| |
| )
| |
| self.system_temp = Pmw.EntryField(group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'System Temperature:',
| |
| validate = {'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['system_temp']),
| |
| )
| |
| self.sdens = Pmw.EntryField(group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Vacc sphere density (grid points/A^2)',
| |
| validate = {'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['sdens']),
| |
| )
| |
| self.bcfl = Pmw.OptionMenu(group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Boundary Condition',
| |
| items = ('Zero','Single DH sphere','Multiple DH spheres',), #'Focusing',),
| |
| initialitem = APBSTools2.defaults['bcfl'],
| |
| )
| |
| self.chgm = Pmw.OptionMenu(group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Charge disc method',
| |
| items = ('Linear','Cubic B-splines','Quintic B-splines',),
| |
| initialitem = APBSTools2.defaults['chgm'],
| |
| )
| |
| self.srfm = Pmw.OptionMenu(group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Surface Calculation Method',
| |
| items = ('Mol surf for epsilon; inflated VdW for kappa, no smoothing','Same, but with harmonic average smoothing','Cubic spline','Similar to cubic spline, but with 7th order polynomial'),
| |
| initialitem = 'Same, but with harmonic average smoothing',
| |
| )
| |
| #for entry in (self.apbs_mode,self.system_temp,self.solvent_radius,):
| |
| for entry in (self.max_mem_allowed,self.solvent_radius,self.system_temp,self.sdens,self.apbs_mode,self.bcfl,self.chgm,self.srfm):
| |
| entry.pack(fill='x',expand=1,padx=4,pady=1) # vertical
| |
|
| |
|
| |
| group = Pmw.Group(page,tag_text='Ions')
| |
| group.pack(fill='both',expand=1, padx=4, pady=5)
| |
| group.grid(column=0, row=1, )
| |
| self.ion_plus_one_conc = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Concentration (M) (+1):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_plus_one_conc']),
| |
| )
| |
| self.ion_plus_one_rad = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Radius (+1):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_plus_one_rad']),
| |
| )
| |
| self.ion_minus_one_conc = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Concentration (M) (-1):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_minus_one_conc']),
| |
| )
| |
| self.ion_minus_one_rad = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Radius (-1):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_minus_one_rad']),
| |
| )
| |
| self.ion_plus_two_conc = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Concentration (M) (+2):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_plus_two_conc']),
| |
| )
| |
| self.ion_plus_two_rad = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Radius (+2):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_plus_two_rad']),
| |
| )
| |
| self.ion_minus_two_conc = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Concentration (M) (-2):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_minus_two_conc']),
| |
| )
| |
| self.ion_minus_two_rad = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text='Ion Radius (-2):',
| |
| validate={'validator':'real','min':0},
| |
| value = str(APBSTools2.defaults['ion_minus_two_rad']),
| |
| )
| |
| entries = (self.ion_plus_one_conc,self.ion_plus_one_rad,
| |
| self.ion_minus_one_conc,self.ion_minus_one_rad,
| |
| self.ion_plus_two_conc,self.ion_plus_two_rad,
| |
| self.ion_minus_two_conc,self.ion_minus_two_rad,
| |
| )
| |
| for entry in entries:
| |
| entry.pack(fill='x',expand=1,padx=4)
| |
|
| |
| group = Pmw.Group(page,tag_text = 'Coarse Mesh Length')
| |
| group.pack(fill = 'both', expand = 1, padx = 4, pady = 5)
| |
| group.grid(column = 1, row = 0)
| |
| for coord in 'x y z'.split():
| |
| setattr(self,'grid_coarse_%s'%coord,Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text=coord,
| |
| validate={'validator':'real','min':0},
| |
| value = -1,
| |
| entry_width=15,
| |
| )
| |
| )
| |
| getattr(self,'grid_coarse_%s'%coord).pack(fill='x', expand=1, padx=4, pady=1)
| |
|
| |
|
| |
| group = Pmw.Group(page,tag_text = 'Fine Mesh Length')
| |
| group.pack(fill = 'both', expand = 1, padx = 4, pady = 5)
| |
| group.grid(column = 2, row = 0)
| |
| for coord in 'x y z'.split():
| |
| setattr(self,'grid_fine_%s'%coord,Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text=coord,
| |
| validate={'validator':'real','min':0},
| |
| value = -1,
| |
| entry_width=15,
| |
| )
| |
| )
| |
| getattr(self,'grid_fine_%s'%coord).pack(fill='x', expand=1, padx=4, pady=1)
| |
|
| |
|
| |
| group = Pmw.Group(page,tag_text = 'Grid Center')
| |
| group.pack(fill = 'both', expand = 1, padx = 4, pady = 5)
| |
| group.grid(column = 3, row = 0)
| |
| for coord in 'x y z'.split():
| |
| setattr(self,'grid_center_%s'%coord,Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text=coord,
| |
| validate={'validator':'real'},
| |
| value = 0,
| |
| entry_width=10,
| |
| )
| |
| )
| |
| getattr(self,'grid_center_%s'%coord).pack(fill='x', expand=1, padx=4, pady=1)
| |
|
| |
| group = Pmw.Group(page,tag_text = 'Grid Points')
| |
| group.pack(fill = 'both', expand = 1, padx = 4, pady = 5)
| |
| group.grid(column = 4, row = 0)
| |
| for coord in 'x y z'.split():
| |
| setattr(self,'grid_points_%s'%coord,Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_text=coord,
| |
| validate={'validator':'integer','min':0},
| |
| value = -1,
| |
| entry_width=8,
| |
| )
| |
| )
| |
| getattr(self,'grid_points_%s'%coord).pack(fill='x', expand=1, padx=4, pady=1)
| |
|
| |
|
| |
| page.grid_rowconfigure(2,weight=1)
| |
| page.grid_columnconfigure(5,weight=1)
| |
| page = self.notebook.add('Program Locations')
| |
| group = Pmw.Group(page,tag_text='Locations')
| |
| group.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
| def quickFileValidation(s):
| |
| if s == '': return Pmw.PARTIAL
| |
| elif os.path.isfile(s): return Pmw.OK
| |
| elif os.path.exists(s): return Pmw.PARTIAL
| |
| else: return Pmw.PARTIAL
| |
| def quickFileDirValidation(s):
| |
| '''
| |
| assumes s ends in filename
| |
| '''
| |
| if os.path.exists(s) and not os.path.isfile(s):
| |
| return Pmw.PARTIAL
| |
| if os.path.isdir(os.path.split(s)[0]):
| |
| return Pmw.OK
| |
| return Pmw.PARTIAL
| |
| self.binary = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setBinaryLocation),
| |
| validate = {'validator':quickFileValidation,},
| |
| value = get_default_location('apbs.exe'),
| |
| label_text = 'APBS binary location:',
| |
| )
| |
| self.binary.pack(fill = 'x', padx = 20, pady = 10)
| |
| self.psize = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setPsizeLocation),
| |
| validate = {'validator':quickFileValidation,},
| |
| #value = '/usr/local/apbs-0.3.1/tools/manip/psize.py',
| |
| value = get_default_location('psize.py'),
| |
| label_text = 'APBS psize.py location:',
| |
| )
| |
| self.psize.pack(fill = 'x', padx = 20, pady = 10)
| |
| self.pdb2pqr = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setPdb2pqrLocation),
| |
| validate = {'validator':quickFileValidation,},
| |
| value = get_default_location('pdb2pqr.py'),
| |
| label_text = 'pdb2pqr location:',
| |
| )
| |
| self.pdb2pqr.pack(fill = 'x', padx = 20, pady = 10)
| |
|
| |
| label = Tkinter.Label(group.interior(),
| |
| pady = 10,
| |
| justify=LEFT,
| |
| text = """
| |
| The PyMOL APBS tools can calculate proper grid dimensions and spacing (we attempt to make
| |
| the fine mesh spacing 0.5A or finer, but we will make it coarser if forced to by the
| |
| Maximum Grid Points setting in the configuration pane). If you wish to use APBS's psize.py
| |
| to set up the grid, make sure that the path is set correctly above.
| |
|
| |
| PyMOL can generate PQR files using standard protein residues and AMBER charges. If you
| |
| wish to use PDB2PQR instead, make sure that it is installed and that the path is set
| |
| correctly above.
| |
|
| |
| If PyMOL does not automatically find apbs, psize.py, or pdb2pqr, you may set the environment
| |
| variables APBS_BINARY, APBS_PSIZE and APBS_PDB2PQR to point to them respectively.
| |
| """,
| |
| )
| |
| label.pack()
| |
|
| |
|
| |
| page = self.notebook.add('Temp File Locations')
| |
| group = Pmw.Group(page,tag_text='Locations')
| |
| group.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
| self.pymol_generated_pqr_filename = Pmw.EntryField(group.interior(),
| |
| labelpos = 'w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setPymolGeneratedPqrFilename),
| |
| validate = {'validator':quickFileDirValidation,},
| |
| label_text = 'Temporary PQR file: ',
| |
| value = os.path.join(get_default_location('temp'),'pymol-generated.pqr'),
| |
| )
| |
| self.pymol_generated_pqr_filename.pack(fill = 'x', padx = 20, pady = 10)
| |
|
| |
| self.pymol_generated_pdb_filename = Pmw.EntryField(group.interior(),
| |
| labelpos = 'w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setPymolGeneratedPdbFilename),
| |
| validate = {'validator':quickFileDirValidation,},
| |
| label_text = 'Temporary PDB file: ',
| |
| value = os.path.join(get_default_location('temp'),'pymol-generated.pdb'),
| |
| )
| |
| self.pymol_generated_pdb_filename.pack(fill = 'x', padx = 20, pady = 10)
| |
|
| |
| self.pymol_generated_dx_filename = Pmw.EntryField(group.interior(),
| |
| labelpos = 'w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setPymolGeneratedDxFilename),
| |
| validate = {'validator':quickFileDirValidation,},
| |
| label_text = 'Temporary DX file: ',
| |
| value = os.path.join(get_default_location('temp'),'pymol-generated.dx'),
| |
| )
| |
| self.pymol_generated_dx_filename.pack(fill = 'x', padx = 20, pady = 10)
| |
|
| |
|
| |
| self.pymol_generated_in_filename = Pmw.EntryField(group.interior(),
| |
| labelpos='w',
| |
| label_pyclass = FileDialogButtonClassFactory.get(self.setPymolGeneratedInFilename),
| |
| validate = {'validator':quickFileDirValidation,},
| |
| value = os.path.join(get_default_location('temp'),'pymol-generated.in'),
| |
| label_text = 'APBS input file:')
| |
| self.pymol_generated_in_filename.pack(fill = 'x', padx = 20, pady = 10)
| |
| label = Tkinter.Label(group.interior(),
| |
| pady = 10,
| |
| justify=LEFT,
| |
| text = """You can automatically set the default location of temporary files
| |
| by setting the environment variable TEMP.
| |
| """,
| |
| )
| |
| label.pack()
| |
| # Create the visualization pages
| |
| page = self.notebook.add('Visualization (1)')
| |
| group = VisualizationGroup(page,tag_text='Visualization',visgroup_num=1)
| |
| self.visualization_group_1 = group
| |
| group.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
|
| |
| page = self.notebook.add('Visualization (2)')
| |
| group = VisualizationGroup(page,tag_text='Visualization',visgroup_num=2)
| |
| self.visualization_group_2 = group
| |
| group.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
|
| |
| # Create a couple of other empty pages
| |
| page = self.notebook.add('About')
| |
| group = Pmw.Group(page, tag_text='About PyMOL APBS Tools')
| |
| group.pack(fill = 'both', expand = 1, padx = 10, pady = 5)
| |
| text = """This plugin integrates PyMOL (http://PyMOL.org/) with APBS (http://www.poissonboltzmann.org/apbs/).
| |
|
| |
| Documentation may be found at
| |
| http://pymolwiki.org/index.php/APBS
| |
| and
| |
| http://apbs.wustl.edu/MediaWiki/index.php/APBS_electrostatics_in_PyMOL
| |
|
| |
| It requires APBS version >= 0.5.0.
| |
|
| |
| In the simplest case,
| |
|
| |
| 1) Load a structure into PyMOL.
| |
| 2) Start this plugin.
| |
| 3) Make sure that the path to the APBS binary is correct on the "Program Locations" tab.
| |
| 4) Click the "Set grid" button to set up the grid.
| |
| 5) Click the "Run APBS" button.
| |
|
| |
| Many thanks to
| |
| - Warren DeLano and Jason Vertrees for everything involving PyMOL
| |
| - Nathan Baker, Todd Dolinsky and David Gohara for everything involving APBS
| |
| - William G. Scott for help with several APBS+PyMOL issues and documentation
| |
|
| |
| Created by Michael Lerner (http://pymolwiki.org/index.php/User:Mglerner) mglerner@gmail.com
| |
| Carlson Group, University of Michigan (http://www.umich.edu/~carlsonh/)
| |
|
| |
| Please contact the author and cite this plugin if you use it in a publication.
| |
|
| |
| Citation for this plugin:
| |
| MG Lerner and HA Carlson. APBS plugin for PyMOL, 2006,
| |
| University of Michigan, Ann Arbor.
| |
|
| |
| Citation for PyMOL may be found here:
| |
| http://pymol.sourceforge.net/faq.html#CITE
| |
|
| |
| Citation for APBS:
| |
| Baker NA, Sept D, Joseph S, Holst MJ, McCammon JA. Electrostatics of
| |
| nanosystems: application to microtubules and the ribosome. Proc.
| |
| Natl. Acad. Sci. USA 98, 10037-10041 2001.
| |
|
| |
| Citation for PDB2PQR:
| |
| Dolinsky TJ, Nielsen JE, McCammon JA, Baker NA.
| |
| PDB2PQR: an automated pipeline for the setup, execution,
| |
| and analysis of Poisson-Boltzmann electrostatics calculations.
| |
| Nucleic Acids Research 32 W665-W667 (2004).
| |
| """
| |
| #
| |
| # Add this as text in a scrollable pane.
| |
| # Code based on Caver plugin
| |
| # http://loschmidt.chemi.muni.cz/caver/index.php
| |
| #
| |
| interior_frame=Frame(group.interior())
| |
| bar=Scrollbar(interior_frame,)
| |
| text_holder=Text(interior_frame,yscrollcommand=bar.set,background="#ddddff",font="Times 14")
| |
| bar.config(command=text_holder.yview)
| |
| text_holder.insert(END,text)
| |
| text_holder.pack(side=LEFT,expand="yes",fill="both")
| |
| bar.pack(side=LEFT,expand="yes",fill="y")
| |
| interior_frame.pack(expand="yes",fill="both")
| |
|
| |
| self.notebook.setnaturalsize()
| |
| self.showAppModal()
| |
|
| |
| def showAppModal(self):
| |
| #self.dialog.activate() #geometry = 'centerscreenfirst',globalMode = 'nograb')
| |
| self.dialog.show()
| |
| def execute(self, result, refocus=True):
| |
| if result == 'Register APBS Use':
| |
| import webbrowser
| |
| webbrowser.open("http://agave.wustl.edu/apbs/download")
| |
| elif result == 'Register PDB2PQR Use':
| |
| import webbrowser
| |
| webbrowser.open("http://www.poissonboltzmann.org/pdb2pqr/d/downloads")
| |
| elif result == 'Run APBS':
| |
| good = self.generateApbsInputFile()
| |
| if not good:
| |
| if DEBUG:
| |
| print "ERROR: Something went wrong trying to generate the APBS input file."
| |
| return False
| |
| if self.radiobuttons.getvalue() == 'Use another PQR':
| |
| pass
| |
| elif self.radiobuttons.getvalue() == 'Use PDB2PQR':
| |
| if DEBUG: print "GENERATING PQR FILE via PDB2PQR"
| |
| good = self.generatePdb2pqrPqrFile()
| |
| if not good:
| |
| if DEBUG:
| |
| print "Could not generate PDB2PQR file. generatePdb2pqrPqrFile failed."
| |
| return False
| |
| if DEBUG: print "GENERATED"
| |
| else: # it's one of the pymol-generated options
| |
| if DEBUG: print "GENERATING PQR FILE via PyMOL"
| |
| good = self.generatePymolPqrFile()
| |
| if not good:
| |
| if DEBUG:
| |
| print "Could not generate the PyMOL-basd PQR file. generatePyMOLPqrFile failed."
| |
| return False
| |
| if DEBUG: print "GENERATED"
| |
| if os.path.exists(self.pymol_generated_dx_filename.getvalue()):
| |
| try:
| |
| os.unlink(self.pymol_generated_dx_filename.getvalue())
| |
| except:
| |
| traceback.print_exc()
| |
| pass
| |
| #command = "%s %s" % (self.binary.getvalue(),self.pymol_generated_in_filename.getvalue())
| |
| #os.system(command)
| |
|
| |
| #
| |
| # NOTE: if there are spaces in the directory name that contains pymol_generated_in_filename,
| |
| # our run command will want to split it up into several arguments if we pass it as a
| |
| # string. So, we pass it as a tuple.
| |
| #
| |
| (retval,progout) = run(self.binary.getvalue(),(self.pymol_generated_in_filename.getvalue(),))
| |
| if refocus:
| |
| #
| |
| # There's a bug in the version of APBS shipped with
| |
| # Ubuntu 9.10 (version 1.1.0) that causes the name to
| |
| # become foo-PE0.dx instead of foo.dx. This would
| |
| # normally only occur in mg-para calcs or MPI versions
| |
| # of apbs. It's clearly bug-possible, but we will
| |
| # check for foo-PE0 if we can't find foo.dx.
| |
| #
| |
| fname = self.pymol_generated_dx_filename.getvalue()
| |
| if not os.path.isfile(fname):
| |
| print "Could not find",fname,"so searching for",
| |
| fname = '-PE0'.join(os.path.splitext(fname))
| |
| print fname
| |
| pymol.cmd.load(fname)
| |
| self.visualization_group_1.refresh()
| |
| self.visualization_group_2.refresh()
| |
| self.notebook.tab('Visualization (1)').focus_set()
| |
| self.notebook.selectpage('Visualization (1)')
| |
| elif result == 'Set grid':
| |
| self.runPsize()
| |
| else:
| |
| #
| |
| # Doing it this way takes care of clicking on the x in the top of the
| |
| # window, which as result set to None.
| |
| #
| |
| global APBS_BINARY_LOCATION, APBS_PSIZE_LOCATION
| |
| APBS_BINARY_LOCATION = self.binary.getvalue()
| |
| APBS_PSIZE_LOCATION = self.psize.getvalue()
| |
| self.quit()
| |
| def quit(self):
| |
| self.dialog.destroy() # stops CPU hogging, perhaps fixes Ubuntu bug MGL
| |
|
| |
| def runPsize(self):
| |
| class NoPsize(Exception):
| |
| pass
| |
| class NoPDB(Exception):
| |
| pass
| |
| try:
| |
| if not self.psize.valid():
| |
| raise NoPsize
| |
| pqr_filename = self.pymol_generated_pqr_filename.getvalue()
| |
| try:
| |
| f = file(pqr_filename,'w')
| |
| f.close()
| |
| except:
| |
| raise NoPDB
| |
| #
| |
| # Do some magic to load the psize module
| |
| #
| |
| import imp
| |
| f,fname,description = imp.find_module('psize',[os.path.split(self.psize.getvalue())[0]])
| |
| psize = imp.load_module('psize',f,fname,description)
| |
| # WLD
| |
| sel = "((%s) or (neighbor (%s) and hydro))"%(
| |
| self.selection.getvalue(), self.selection.getvalue())
| |
|
| |
| if pymol.cmd.count_atoms( self.selection.getvalue() + " and not alt ''")!=0:
| |
| print "WARNING: You have alternate locations for some of your atoms!"
| |
| pymol.cmd.save(pqr_filename,sel)
| |
| f.close()
| |
| size = psize.Psize()
| |
| size.setConstant('gmemceil',int(self.max_mem_allowed.getvalue()))
| |
| size.runPsize(pqr_filename)
| |
| coarsedim = size.getCoarseGridDims() # cglen
| |
| finedim = size.getFineGridDims() # fglen
| |
| # could use procgrid for multiprocessors
| |
| finegridpoints = size.getFineGridPoints() # dime
| |
| center = size.getCenter() # cgcent and fgcent
| |
| print "APBS's psize.py was used to calculated grid dimensions"
| |
| except (NoPsize,ImportError):
| |
| print "This plugin was used to calculated grid dimensions"
| |
| #
| |
| # First, we need to get the dimensions of the molecule
| |
| #
| |
| # WLD
| |
| sel = "((%s) or (neighbor (%s) and hydro))"%(
| |
| self.selection.getvalue(), self.selection.getvalue())
| |
| model = pymol.cmd.get_model(sel)
| |
| mins = [None,None,None]
| |
| maxs = [None,None,None]
| |
| for a in model.atom:
| |
| for i in (0,1,2):
| |
| if mins[i] is None or a.coord[i] < mins[i]:
| |
| mins[i] = a.coord[i]
| |
| if maxs[i] is None or a.coord[i] > maxs[i]:
| |
| maxs[i] = a.coord[i]
| |
| if None in mins or None in maxs:
| |
| error_dialog = Pmw.MessageDialog(self.parent,
| |
| title = 'Error',
| |
| message_text = "No atoms were in your selection",
| |
| )
| |
| junk = error_dialog.activate()
| |
| return False
| |
|
| |
| box_length = [maxs[i] - mins[i] for i in range(3)]
| |
| center = [(maxs[i] + mins[i])/2.0 for i in range(3)]
| |
| #
| |
| # psize expands the molecular dimensions by CFAC (which defaults
| |
| # to 1.7) for the coarse grid
| |
| #
| |
| CFAC = 1.7
| |
| coarsedim = [length*CFAC for length in box_length]
| |
|
| |
| #
| |
| # psize also does something strange .. it adds a buffer FADD to
| |
| # the box lengths to get the fine lengths. you'd think it'd also
| |
| # have FFAC or CADD, but we'll mimic it here. it also has the
| |
| # requirement that the fine grid lengths must be <= the corase
| |
| # grid lengths. FADD defaults to 20.
| |
| #
| |
| FADD = 20
| |
| finedim = [min(coarsedim[i],box_length[i] + FADD) for i in range(3)]
| |
|
| |
| #
| |
| # And now the hard part .. setting up the grid points.
| |
| # From the APBS manual at http://agave.wustl.edu/apbs/doc/html/user-guide/x594.html#dime
| |
| # we have the formula
| |
| # n = c*2^(l+1) + 1
| |
| # where l is the number of levels in the MG hierarchy. The typical
| |
| # number of levels is 4.
| |
| #
| |
| nlev = 4
| |
| mult_fac = 2**(nlev + 1) # this will typically be 2^5==32
| |
| # and c must be a non-zero integer
| |
|
| |
| # If we didn't have to be c*mult_fac + 1, this is what our grid points
| |
| # would look like (we use the ceiling to be on the safe side .. it never
| |
| # hurts to do too much.
| |
| SPACE = 0.5 # default desired spacing = 0.5A
| |
| #desired_points = [int(math.ceil(flen / SPACE)) for flen in finedim] # as integers
| |
| desired_points = [flen / SPACE for flen in finedim] # as floats .. use int(math.ceil(..)) later
| |
|
| |
| # Now we set up our cs, taking into account mult_fac
| |
| # (we use the ceiling to be on the safe side .. it never hurts to do
| |
| # too much.)
| |
| cs = [int(math.ceil(dp/mult_fac)) for dp in desired_points]
| |
|
| |
| finegridpoints = [mult_fac * c + 1 for c in cs]
| |
|
| |
| print "cs",cs
| |
| print "finedim",finedim
| |
| print "nlev",nlev
| |
| print "mult_fac",mult_fac
| |
| print "finegridpoints",finegridpoints
| |
|
| |
| except NoPDB:
| |
| error_dialog = Pmw.MessageDialog(self.parent,
| |
| title = 'Error',
| |
| message_text = "Please set a temporary PDB file location",
| |
| )
| |
| junk = error_dialog.activate()
| |
| return False
| |
|
| |
| if (finegridpoints[0]>0) and (finegridpoints[1]>0) and (finegridpoints[2]>0):
| |
| max_mem_allowed = float(self.max_mem_allowed.getvalue())
| |
| def memofgrid(finegridpoints):
| |
| return 200. * float(finegridpoints[0] * finegridpoints[1] * finegridpoints[2]) / 1024. / 1024
| |
| def gridofmem(mem):
| |
| return mem * 1024. * 1024. / 200.
| |
| max_grid_points = gridofmem(max_mem_allowed)
| |
| print "Estimated memory usage",memofgrid(finegridpoints),'MB out of maximum allowed',max_mem_allowed
| |
| if memofgrid(finegridpoints) > max_mem_allowed:
| |
| print "Maximum memory usage exceeded. Old grid dimensions were",finegridpoints
| |
| product = float(finegridpoints[0] * finegridpoints[1] * finegridpoints[2])
| |
| factor = pow(max_grid_points/product,0.333333333)
| |
| finegridpoints[0] = (int(factor*finegridpoints[0]/2))*2+1
| |
| finegridpoints[1] = (int(factor*finegridpoints[1]/2))*2+1
| |
| finegridpoints[2] = (int(factor*finegridpoints[2]/2))*2+1
| |
| print "Fine grid points rounded down from",finegridpoints
| |
| #
| |
| # Now we have to make sure that this still fits the equation n = c*2^(l+1) + 1. Here, we'll
| |
| # just assume nlev == 4, which means that we need to be (some constant times 32) + 1.
| |
| #
| |
| # This can be annoying if, e.g., you're trying to set [99, 123, 99] .. it'll get rounded to [99, 127, 99].
| |
| # First, I'll try to round to the nearest 32*c+1. If that doesn't work, I'll just round down.
| |
| #
| |
| new_gp = [0,0,0]
| |
| for i in 0,1,2:
| |
| dm = divmod(finegridpoints[i] - 1,32)
| |
| if dm[1]>16:
| |
| new_gp[i] = (dm[0]+1)*32+1
| |
| else:
| |
| new_gp[i] = (dm[0])*32+1
| |
| new_prod = new_gp[0]*new_gp[1]*new_gp[2]
| |
| #print "tried new_prod",new_prod,"max_grid_points",max_grid_points,"small enough?",new_prod <= max_grid_points
| |
| if new_prod <= max_grid_points:
| |
| #print "able to round to closest"
| |
| for i in 0,1,2: finegridpoints[i] = new_gp[i]
| |
| else:
| |
| # darn .. have to round down.
| |
| # Note that this can still fail a little bit .. it can only get you back down to the next multiple <= what was in
| |
| # finegridpoints. So, if finegridpoints was exactly on a multiple, like (99,129,99), you'll get rounded down to
| |
| # (99,127,99), which is still just a bit over the default max of 1200000. I think that's ok. It's the rounding error
| |
| # from int(factor*finegridpoints ..) above, but it'll never be a huge error. If we needed to, we could easily fix this.
| |
| #
| |
| #print "rounding down more"
| |
| for i in 0,1,2:
| |
| #print finegridpoints[i],divmod(finegridpoints[i] - 1,32),
| |
| finegridpoints[i] = divmod(finegridpoints[i] - 1,32)[0]*32 + 1
| |
| print "New grid dimensions are",finegridpoints
| |
| print " APBS Tools: coarse grid: (%5.3f,%5.3f,%5.3f)"%tuple(coarsedim)
| |
| self.grid_coarse_x.setvalue(coarsedim[0])
| |
| self.grid_coarse_y.setvalue(coarsedim[1])
| |
| self.grid_coarse_z.setvalue(coarsedim[2])
| |
| print " APBS Tools: fine grid: (%5.3f,%5.3f,%5.3f)"%tuple(finedim)
| |
| self.grid_fine_x.setvalue(finedim[0])
| |
| self.grid_fine_y.setvalue(finedim[1])
| |
| self.grid_fine_z.setvalue(finedim[2])
| |
| print " APBS Tools: center: (%5.3f,%5.3f,%5.3f)"%tuple(center)
| |
| self.grid_center_x.setvalue(center[0])
| |
| self.grid_center_y.setvalue(center[1])
| |
| self.grid_center_z.setvalue(center[2])
| |
| print " APBS Tools: fine grid points (%d,%d,%d)"%tuple(finegridpoints)
| |
| self.grid_points_x.setvalue(finegridpoints[0])
| |
| self.grid_points_y.setvalue(finegridpoints[1])
| |
| self.grid_points_z.setvalue(finegridpoints[2])
| |
|
| |
| def fixColumns(self,sel):
| |
| """
| |
| Make sure that everything fits into the correct columns.
| |
| This means doing some rounding. It also means getting rid of
| |
| chain, occupancy and b-factor information.
| |
| """
| |
| #pymol.cmd.alter_state(1,'all','(x,y,z)=(int(x*1000)/1000.0, int(y*1000)/1000.0, int(z*1000)/1000.0)')
| |
| #pymol.cmd.alter_state(1,'all','(x,y,z)=float("%.2f"%x),float("%.2f"%y),float("%.2f"%z)')
| |
| pymol.cmd.alter_state(1,'all','(x,y,z)=float("%.3f"%x),float("%.3f"%y),float("%.3f"%z)')
| |
| pymol.cmd.alter(sel,'chain=""')
| |
| pymol.cmd.alter(sel,'b=0')
| |
| pymol.cmd.alter(sel,'q=0')
| |
|
| |
| def cleanupGeneratedPdbOrPqrFile(self,filename):
| |
| """
| |
| More cleanup on PQR files.
| |
|
| |
| pdb2pqr will happily write out a file where the coordinate
| |
| columns overlap if you have -100.something as one of the
| |
| coordinates, like
| |
|
| |
| 90.350 97.230-100.010
| |
|
| |
| and so will PyMOL. We can't just assume that it's 0-1
| |
| because pdb2pqr will debump things and write them out with
| |
| 3 digits post-decimal. Bleh.
| |
| """
| |
| f = file(filename,'r')
| |
| txt = f.read()
| |
| f.close()
| |
| f = file(filename,'w')
| |
| # APBS accepts whitespace-delimited columns
| |
| # it doesn't care about non-coord lines, so there's not need to be careful about
| |
| # where we replace dashes.
| |
| txt = txt.replace('-',' -')
| |
| f.write(txt)
| |
| f.close()
| |
|
| |
| def getUnassignedAtomsFromPqr(self,fname):
| |
| """
| |
| Here is a comment from Todd Dolinsky via email:
| |
|
| |
| There's a couple of different errors which can be printed out via REMARK 5 lines; a good sample is:
| |
|
| |
| REMARK 1 PQR file generated by PDB2PQR (Version 1.2.0)
| |
| REMARK 1
| |
| REMARK 1 Forcefield Used: charmm
| |
| REMARK 1
| |
| REMARK 1 pKas calculated by propka and assigned using pH 7.00
| |
| REMARK 1
| |
| REMARK 5 WARNING: Propka determined the following residues to be
| |
| REMARK 5 in a protonation state not supported by the
| |
| REMARK 5 charmm forcefield!
| |
| REMARK 5 All were reset to their standard pH 7.0 state.
| |
| REMARK 5
| |
| REMARK 5 CYS 61 2 (negative)
| |
| REMARK 5 CYS 79 2 (negative)
| |
| REMARK 5
| |
| REMARK 5 WARNING: Unable to debump ALA 1 19
| |
| REMARK 5 WARNING: Unable to debump MET 1 151
| |
| REMARK 5 WARNING: Unable to debump PRO 1 258
| |
| REMARK 5 WARNING: Unable to debump GLY 2 8
| |
| REMARK 5 WARNING: Unable to debump THR 3 118
| |
| REMARK 5
| |
| REMARK 5 WARNING: PDB2PQR was unable to assign charges
| |
| REMARK 5 to the following atoms (omitted below):
| |
| REMARK 5 6657 O1 in TRS 900
| |
| REMARK 5 6658 C2 in TRS 900
| |
| REMARK 5 6659 C3 in TRS 900
| |
| REMARK 5 6660 C4 in TRS 900
| |
| REMARK 5 6661 O5 in TRS 900
| |
| REMARK 5 6662 C6 in TRS 900
| |
| REMARK 5 6663 O7 in TRS 900
| |
| REMARK 5 6664 N8 in TRS 900
| |
| REMARK 5
| |
| REMARK 6 Total charge on this protein: -1.0000 e
| |
| REMARK 6
| |
|
| |
| If all you care about is the atom number, you can probably regexp match on the 'in' field, something like
| |
|
| |
| >>> re.compile('REMARK 5 *(\d)* \w* in').findall(text) # Text contains PQR output string
| |
| ['6657', '6658', '6659', '6660', '6661', '6662', '6663', '6664']
| |
|
| |
| Or you can grab any other useful information - I'd say that using a regular expression like this would be the best option to ensure you don't get false positives.
| |
| """
| |
| f = file(fname)
| |
| unassigned = re.compile('REMARK 5 *(\d+) \w* in').findall(f.read()) # Text contains PQR output string
| |
| f.close()
| |
| return '+'.join(unassigned)
| |
|
| |
|
| |
| def generateApbsInputFile(self):
| |
| if self.checkInput(silent=False):
| |
| #
| |
| # set up our variables
| |
| #
| |
| pqr_filename = self.getPqrFilename()
| |
|
| |
| grid_points = [int(getattr(self,'grid_points_%s'%i).getvalue()) for i in 'x y z'.split()]
| |
| cglen = [float(getattr(self,'grid_coarse_%s'%i).getvalue()) for i in 'x y z'.split()]
| |
| fglen = [float(getattr(self,'grid_fine_%s'%i).getvalue()) for i in 'x y z'.split()]
| |
| cent = [float(getattr(self,'grid_center_%s'%i).getvalue()) for i in 'x y z'.split()]
| |
|
| |
| apbs_mode = self.apbs_mode.getvalue()
| |
| if apbs_mode == 'Nonlinear Poisson-Boltzmann Equation':
| |
| apbs_mode = 'npbe'
| |
| else:
| |
| apbs_mode = 'lpbe'
| |
|
| |
| bcflmap = {'Zero': 'zero',
| |
| 'Single DH sphere': 'sdh',
| |
| 'Multiple DH spheres': 'mdh',
| |
| #'Focusing': 'focus',
| |
| }
| |
| bcfl = bcflmap[self.bcfl.getvalue()]
| |
|
| |
| chgmmap = {'Linear':'spl0',
| |
| 'Cubic B-splines':'spl2',
| |
| 'Quintic B-splines':'spl4',
| |
| }
| |
| chgm = chgmmap[self.chgm.getvalue()]
| |
|
| |
| srfmmap = {'Mol surf for epsilon; inflated VdW for kappa, no smoothing':'mol',
| |
| 'Same, but with harmonic average smoothing':'smol',
| |
| 'Cubic spline':'spl2',
| |
| 'Similar to cubic spline, but with 7th order polynomial':'spl4',}
| |
|
| |
| srfm = srfmmap[self.srfm.getvalue()]
| |
|
| |
| dx_filename = self.pymol_generated_dx_filename.getvalue()
| |
| if dx_filename.endswith('.dx'):
| |
| dx_filename = dx_filename[:-3]
| |
| apbs_input_text = getApbsInputFile(pqr_filename,
| |
| grid_points,
| |
| cglen,
| |
| fglen,
| |
| cent,
| |
| apbs_mode,
| |
| bcfl,
| |
| float(self.ion_plus_one_conc.getvalue()), float(self.ion_plus_one_rad.getvalue()),
| |
| float(self.ion_minus_one_conc.getvalue()), float(self.ion_minus_one_rad.getvalue()),
| |
| float(self.ion_plus_two_conc.getvalue()), float(self.ion_plus_two_rad.getvalue()),
| |
| float(self.ion_minus_two_conc.getvalue()), float(self.ion_minus_two_rad.getvalue()),
| |
| float(self.interior_dielectric.getvalue()), float(self.solvent_dielectric.getvalue()),
| |
| chgm,
| |
| srfm,
| |
| float(self.solvent_radius.getvalue()),
| |
| float(self.system_temp.getvalue()),
| |
| float(self.sdens.getvalue()),
| |
| dx_filename,
| |
| )
| |
| if DEBUG:
| |
| print "GOT THE APBS INPUT FILE"
| |
|
| |
| #
| |
| # write out the input text
| |
| #
| |
| try:
| |
| f = file(self.pymol_generated_in_filename.getvalue(),'w')
| |
| f.write(apbs_input_text)
| |
| f.close()
| |
| except IOError:
| |
| print "ERROR: Got the input file from APBS, but failed when trying to write to %s" % self.pymol_generated_in_filename.getvalue()
| |
| return True
| |
| else:
| |
| self.checkInput()
| |
| return False
| |
|
| |
| def checkInput(self,silent=False):
| |
| """If silent is True, we'll just return a True/False value
| |
| """
| |
| if not silent:
| |
| def show_error(message):
| |
| error_dialog = Pmw.MessageDialog(self.parent,
| |
| title = 'Error',
| |
| message_text = message,
| |
| )
| |
| junk = error_dialog.activate()
| |
| else:
| |
| def show_error(message):
| |
| pass
| |
|
| |
| #
| |
| # First, check to make sure we have valid locations for apbs and psize
| |
| #
| |
| if not self.binary.valid():
| |
| show_error('Please set the APBS binary location')
| |
| return False
| |
| #
| |
| # If the path to psize is not correct, that's fine .. we'll
| |
| # do the calculations ourself.
| |
| #
| |
|
| |
| #if not self.psize.valid():
| |
| # show_error("Please set APBS's psize location")
| |
| # return False
| |
|
| |
| #
| |
| # Now check the temporary filenames
| |
| #
| |
| if self.radiobuttons.getvalue() != 'Use another PQR':
| |
| if not self.pymol_generated_pqr_filename.getvalue():
| |
| show_error('Please choose a name for the PyMOL\ngenerated PQR file')
| |
| return False
| |
| elif not self.pqr_to_use.valid():
| |
| show_error('Please select a valid pqr file or tell\nPyMOL to generate one')
| |
| return False
| |
| if not self.pymol_generated_pdb_filename.getvalue():
| |
| show_error('Please choose a name for the PyMOL\ngenerated PDB file')
| |
| return False
| |
| if not self.pymol_generated_dx_filename.getvalue():
| |
| show_error('Please choose a name for the PyMOL\ngenerated DX file')
| |
| return False
| |
| if not self.pymol_generated_in_filename.getvalue():
| |
| show_error('Please choose a name for the PyMOL\ngenerated APBS input file')
| |
| return False
| |
| if not self.map.getvalue():
| |
| show_error('Please choose a name for the generated map.')
| |
| return False
| |
|
| |
|
| |
| #
| |
| # Now, the ions
| |
| #
| |
| for sign in 'plus minus'.split():
| |
| for value in 'one two'.split():
| |
| for parm in 'conc rad'.split():
| |
| if not getattr(self,'ion_%s_%s_%s'%(sign,value,parm)).valid():
| |
| show_error('Please correct Ion concentrations and radii')
| |
| return False
| |
| #
| |
| # Now the grid
| |
| #
| |
| for grid_type in 'coarse fine points center'.split():
| |
| for coord in 'x y z'.split():
| |
| if not getattr(self,'grid_%s_%s'%(grid_type,coord)).valid():
| |
| show_error('Please correct grid dimensions\nby clicking on the "Set grid" button')
| |
| return False
| |
|
| |
| #
| |
| # Now other easy things
| |
| #
| |
| for (message, thing) in (('solvent dielectric',self.solvent_dielectric),
| |
| ('protein dielectric',self.interior_dielectric),
| |
| ('solvent radius',self.solvent_radius),
| |
| ('system temperature',self.system_temp),
| |
| ('sdens',self.sdens),
| |
| ):
| |
| if not thing.valid():
| |
| show_error('Please correct %s'%message)
| |
| return False
| |
|
| |
| return True
| |
|
| |
|
| |
| def generatePdb2pqrPqrFile(self,silent=False):
| |
| """use pdb2pqr to generate a pqr file
| |
| """
| |
| if not silent:
| |
| def show_error(message):
| |
| error_dialog = Pmw.MessageDialog(self.parent,
| |
| title = 'Error',
| |
| message_text = message,
| |
| )
| |
| junk = error_dialog.activate()
| |
| else:
| |
| def show_error(message):
| |
| pass
| |
|
| |
| #
| |
| # First, generate a PDB file
| |
| #
| |
| pdb_filename = self.pymol_generated_pdb_filename.getvalue()
| |
| try:
| |
| f = file(pdb_filename,'w')
| |
| f.close()
| |
| except:
| |
| show_error('Please set a temporary PDB file location that you have permission to edit')
| |
| return False
| |
| # copied from WLD code
| |
| sel = "((%s) or (neighbor (%s) and hydro))"%(
| |
| self.selection.getvalue(), self.selection.getvalue())
| |
| self.fixColumns(sel)
| |
| pymol.cmd.save(pdb_filename,sel)
| |
| self.cleanupGeneratedPdbOrPqrFile(pdb_filename)
| |
|
| |
| #
| |
| # Now, generate a PQR file
| |
| #
| |
| ## command_line = '%s %s %s %s'%(self.pdb2pqr.getvalue(),
| |
| ## self.pdb2pqr_options.getvalue(),
| |
| ## pdb_filename,
| |
| ## self.pymol_generated_pqr_filename.getvalue(),
| |
| ## )
| |
| ## print "RAN",command_line
| |
| ## result = os.system(command_line)
| |
| #
| |
| # We have to be a little cute about args, because pdb2pqr_options could have several options in it.
| |
| args = '%s %s %s' %(self.pdb2pqr_options.getvalue(),
| |
| pdb_filename,
| |
| self.pymol_generated_pqr_filename.getvalue(),
| |
| )
| |
| (retval,progout) = run(self.pdb2pqr.getvalue(),args)
| |
|
| |
|
| |
| if retval != 0:
| |
| show_error('Could not run pdb2pqr: %s %s\n\n%s'%(self.pdb2pqr.getvalue(),
| |
| args,
| |
| progout)
| |
| )
| |
| return False
| |
| self.cleanupGeneratedPdbOrPqrFile(self.pymol_generated_pqr_filename.getvalue())
| |
| unassigned_atoms = self.getUnassignedAtomsFromPqr(self.pymol_generated_pqr_filename.getvalue())
| |
| if unassigned_atoms:
| |
| pymol.cmd.select('unassigned','ID %s'%unassigned_atoms)
| |
| message_text = "Unable to assign parameters for the %s atoms in selection 'unassigned'.\nPlease either remove these unassigned atoms and re-start the calculation\nor fix their parameters in the generated PQR file and run the calculation\nusing the modified PQR file (select 'Use another PQR' in 'Main')."%len(unassigned_atoms.split('+'))
| |
| print "Unassigned atom IDs",unassigned_atoms
| |
| show_error(message_text)
| |
| return False
| |
| return True
| |
|
| |
|
| |
| def generatePymolPqrFile(self):
| |
| """generate a pqr file from pymol
| |
|
| |
| This will also call through to champ to set the Hydrogens and charges
| |
| if it needs to. If it does that, it may change the value self.selection
| |
| to take the new Hydrogens into account.
| |
|
| |
| To make it worse, APBS seems to freak out when there are chain ids. So,
| |
| this gets rid of the chain ids.
| |
|
| |
| """
| |
| # CHAMP will break in many cases if retain_order is set. So,
| |
| # we unset it here and reset it later. Note that it's fine to
| |
| # reset it before things are written out.
| |
| ret_order = pymol.cmd.get('retain_order')
| |
| pymol.cmd.set('retain_order',0)
| |
|
| |
| # WLD
| |
| sel = "((%s) or (neighbor (%s) and hydro))"%(
| |
| self.selection.getvalue(), self.selection.getvalue())
| |
|
| |
| pqr_filename = self.getPqrFilename()
| |
| try:
| |
| f = file(pqr_filename,'w')
| |
| f.close()
| |
| except:
| |
| error_dialog = Pmw.MessageDialog(self.parent,
| |
| title = 'Error',
| |
| message_text = "Could not write PQR file.\nPlease check that temporary PQR filename is valid.",
| |
| )
| |
| junk = error_dialog.activate()
| |
| return False
| |
|
| |
| # PyMOL + champ == pqr
| |
| from chempy.champ import assign
| |
| if self.radiobuttons.getvalue() == 'Use PyMOL generated PQR and PyMOL generated Hydrogens and termini':
| |
| pymol.cmd.remove('hydro and %s'%sel)
| |
| assign.missing_c_termini(sel)
| |
| assign.formal_charges(sel)
| |
| pymol.cmd.h_add(sel)
| |
| # WLD (code now unnecessary)
| |
| # new_hydros = '(hydro and neighbor %s)'%sel
| |
| # sel = '%s or %s' % (sel,new_hydros)
| |
| assign.amber99(sel)
| |
| pymol.cmd.set('retain_order',ret_order)
| |
|
| |
| # WLD (code now unnecessary)
| |
| # if not self.selection.getvalue() in '(all) all'.split():
| |
| # self.selection.setvalue(sel)
| |
|
| |
| #
| |
| # Get rid of chain information
| |
| #
| |
| # WLD -- PyMOL now does this automatically with PQR files
| |
| # pymol.cmd.alter(sel,'chain = ""')
| |
| self.fixColumns(sel)
| |
| pymol.cmd.save(pqr_filename,sel)
| |
| self.cleanupGeneratedPdbOrPqrFile(pqr_filename)
| |
| missed_count = pymol.cmd.count_atoms("("+sel+") and flag 23")
| |
| if missed_count > 0:
| |
| pymol.cmd.select("unassigned","("+sel+") and flag 23")
| |
| error_dialog = Pmw.MessageDialog(self.parent,
| |
| title = 'Error',
| |
| message_text = "Unable to assign parameters for the %s atoms in selection 'unassigned'.\nPlease either remove these unassigned atoms and re-start the calculation\nor fix their parameters in the generated PQR file and run the calculation\nusing the modified PQR file (select 'Use another PQR' in 'Main')."%missed_count,
| |
| )
| |
| junk = error_dialog.activate()
| |
| return False
| |
| return True
| |
|
| |
|
| |
| ############################################################
| |
| ############################################################
| |
| ############################################################
| |
| ## ##
| |
| ## PmwExtensions ##
| |
| ## ##
| |
| ############################################################
| |
| ############################################################
| |
| ############################################################
| |
|
| |
| """
| |
| This contains all of the visualization groups that we'll use for our
| |
| PMW interface.
| |
| """
| |
|
| |
| #
| |
| # Generically useful PMW extensions
| |
|
| |
| import os,fnmatch,time
| |
| import Tkinter,Pmw
| |
| #Pmw.setversion("0.8.5")
| |
|
| |
| #
| |
| # The classes PmwFileDialog and PmwExistingFileDialog and the _errorpop function
| |
| # are taken from the Pmw contrib directory. The attribution given in that file
| |
| # is:
| |
| ################################################################################
| |
| # Filename dialogs using Pmw
| |
| #
| |
| # (C) Rob W.W. Hooft, Nonius BV, 1998
| |
| #
| |
| # Modifications:
| |
| #
| |
| # J. Willem M. Nissink, Cambridge Crystallographic Data Centre, 8/2002
| |
| # Added optional information pane at top of dialog; if option
| |
| # 'info' is specified, the text given will be shown (in blue).
| |
| # Modified example to show both file and directory-type dialog
| |
| #
| |
| # No Guarantees. Distribute Freely.
| |
| # Please send bug-fixes/patches/features to <r.hooft@euromail.com>
| |
| #
| |
| ################################################################################
| |
|
| |
| def _errorpop(master,text):
| |
| d=Pmw.MessageDialog(master,
| |
| title="Error",
| |
| message_text=text,
| |
| buttons=("OK",))
| |
| d.component('message').pack(ipadx=15,ipady=15)
| |
| d.activate()
| |
| d.destroy()
| |
|
| |
| class PmwFileDialog(Pmw.Dialog):
| |
| """File Dialog using Pmw"""
| |
| def __init__(self, parent = None, **kw):
| |
| # Define the megawidget options.
| |
| optiondefs = (
| |
| ('filter', '*', self.newfilter),
| |
| ('directory', os.getcwd(), self.newdir),
| |
| ('filename', '', self.newfilename),
| |
| ('historylen',10, None),
| |
| ('command', None, None),
| |
| ('info', None, None),
| |
| )
| |
| self.defineoptions(kw, optiondefs)
| |
| # Initialise base class (after defining options).
| |
| Pmw.Dialog.__init__(self, parent)
| |
|
| |
| self.withdraw()
| |
|
| |
| # Create the components.
| |
| interior = self.interior()
| |
|
| |
| if self['info'] is not None:
| |
| rowoffset=1
| |
| dn = self.infotxt()
| |
| dn.grid(row=0,column=0,columnspan=2,padx=3,pady=3)
| |
| else:
| |
| rowoffset=0
| |
|
| |
| dn = self.mkdn()
| |
| dn.grid(row=0+rowoffset,column=0,columnspan=2,padx=3,pady=3)
| |
| del dn
| |
|
| |
| # Create the directory list component.
| |
| dnb = self.mkdnb()
| |
| dnb.grid(row=1+rowoffset,column=0,sticky='news',padx=3,pady=3)
| |
| del dnb
| |
|
| |
| # Create the filename list component.
| |
| fnb = self.mkfnb()
| |
| fnb.grid(row=1+rowoffset,column=1,sticky='news',padx=3,pady=3)
| |
| del fnb
| |
|
| |
| # Create the filter entry
| |
| ft = self.mkft()
| |
| ft.grid(row=2+rowoffset,column=0,columnspan=2,padx=3,pady=3)
| |
| del ft
| |
|
| |
| # Create the filename entry
| |
| fn = self.mkfn()
| |
| fn.grid(row=3+rowoffset,column=0,columnspan=2,padx=3,pady=3)
| |
| fn.bind('<Return>',self.okbutton)
| |
| del fn
| |
|
| |
| # Buttonbox already exists
| |
| bb=self.component('buttonbox')
| |
| bb.add('OK',command=self.okbutton)
| |
| bb.add('Cancel',command=self.cancelbutton)
| |
| del bb
| |
|
| |
| Pmw.alignlabels([self.component('filename'),
| |
| self.component('filter'),
| |
| self.component('dirname')])
| |
|
| |
| def infotxt(self):
| |
| """ Make information block component at the top """
| |
| return self.createcomponent(
| |
| 'infobox',
| |
| (), None,
| |
| Tkinter.Label, (self.interior(),),
| |
| width=51,
| |
| relief='groove',
| |
| foreground='darkblue',
| |
| justify='left',
| |
| text=self['info']
| |
| )
| |
|
| |
| def mkdn(self):
| |
| """Make directory name component"""
| |
| return self.createcomponent(
| |
| 'dirname',
| |
| (), None,
| |
| Pmw.ComboBox, (self.interior(),),
| |
| entryfield_value=self['directory'],
| |
| entryfield_entry_width=40,
| |
| entryfield_validate=self.dirvalidate,
| |
| selectioncommand=self.setdir,
| |
| labelpos='w',
| |
| label_text='Directory:')
| |
|
| |
| def mkdnb(self):
| |
| """Make directory name box"""
| |
| return self.createcomponent(
| |
| 'dirnamebox',
| |
| (), None,
| |
| Pmw.ScrolledListBox, (self.interior(),),
| |
| label_text='directories',
| |
| labelpos='n',
| |
| hscrollmode='none',
| |
| dblclickcommand=self.selectdir)
| |
|
| |
| def mkft(self):
| |
| """Make filter"""
| |
| return self.createcomponent(
| |
| 'filter',
| |
| (), None,
| |
| Pmw.ComboBox, (self.interior(),),
| |
| entryfield_value=self['filter'],
| |
| entryfield_entry_width=40,
| |
| selectioncommand=self.setfilter,
| |
| labelpos='w',
| |
| label_text='Filter:')
| |
|
| |
| def mkfnb(self):
| |
| """Make filename list box"""
| |
| return self.createcomponent(
| |
| 'filenamebox',
| |
| (), None,
| |
| Pmw.ScrolledListBox, (self.interior(),),
| |
| label_text='files',
| |
| labelpos='n',
| |
| hscrollmode='none',
| |
| selectioncommand=self.singleselectfile,
| |
| dblclickcommand=self.selectfile)
| |
|
| |
| def mkfn(self):
| |
| """Make file name entry"""
| |
| return self.createcomponent(
| |
| 'filename',
| |
| (), None,
| |
| Pmw.ComboBox, (self.interior(),),
| |
| entryfield_value=self['filename'],
| |
| entryfield_entry_width=40,
| |
| entryfield_validate=self.filevalidate,
| |
| selectioncommand=self.setfilename,
| |
| labelpos='w',
| |
| label_text='Filename:')
| |
|
| |
| def dirvalidate(self,string):
| |
| if os.path.isdir(string):
| |
| return Pmw.OK
| |
| else:
| |
| return Pmw.PARTIAL
| |
|
| |
| def filevalidate(self,string):
| |
| if string=='':
| |
| return Pmw.PARTIAL
| |
| elif os.path.isfile(string):
| |
| return Pmw.OK
| |
| elif os.path.exists(string):
| |
| return Pmw.PARTIAL
| |
| else:
| |
| return Pmw.OK
| |
|
| |
| def okbutton(self):
| |
| """OK action: user thinks he has input valid data and wants to
| |
| proceed. This is also called by <Return> in the filename entry"""
| |
| fn=self.component('filename').get()
| |
| self.setfilename(fn)
| |
| if self.validate(fn):
| |
| self.canceled=0
| |
| self.deactivate()
| |
|
| |
| def cancelbutton(self):
| |
| """Cancel the operation"""
| |
| self.canceled=1
| |
| self.deactivate()
| |
|
| |
| def tidy(self,w,v):
| |
| """Insert text v into the entry and at the top of the list of
| |
| the combobox w, remove duplicates"""
| |
| if not v:
| |
| return
| |
| entry=w.component('entry')
| |
| entry.delete(0,'end')
| |
| entry.insert(0,v)
| |
| list=w.component('scrolledlist')
| |
| list.insert(0,v)
| |
| index=1
| |
| while index<list.index('end'):
| |
| k=list.get(index)
| |
| if k==v or index>self['historylen']:
| |
| list.delete(index)
| |
| else:
| |
| index=index+1
| |
| w.checkentry()
| |
|
| |
| def setfilename(self,value):
| |
| if not value:
| |
| return
| |
| value=os.path.join(self['directory'],value)
| |
| dir,fil=os.path.split(value)
| |
| self.configure(directory=dir,filename=value)
| |
|
| |
| c=self['command']
| |
| if callable(c):
| |
| c()
| |
|
| |
| def newfilename(self):
| |
| """Make sure a newly set filename makes it into the combobox list"""
| |
| self.tidy(self.component('filename'),self['filename'])
| |
|
| |
| def setfilter(self,value):
| |
| self.configure(filter=value)
| |
|
| |
| def newfilter(self):
| |
| """Make sure a newly set filter makes it into the combobox list"""
| |
| self.tidy(self.component('filter'),self['filter'])
| |
| self.fillit()
| |
|
| |
| def setdir(self,value):
| |
| self.configure(directory=value)
| |
|
| |
| def newdir(self):
| |
| """Make sure a newly set dirname makes it into the combobox list"""
| |
| self.tidy(self.component('dirname'),self['directory'])
| |
| self.fillit()
| |
|
| |
| def singleselectfile(self):
| |
| """Single click in file listbox. Move file to "filename" combobox"""
| |
| cs=self.component('filenamebox').curselection()
| |
| if cs!=():
| |
| value=self.component('filenamebox').get(cs)
| |
| self.setfilename(value)
| |
|
| |
| def selectfile(self):
| |
| """Take the selected file from the filename, normalize it, and OK"""
| |
| self.singleselectfile()
| |
| value=self.component('filename').get()
| |
| self.setfilename(value)
| |
| if value:
| |
| self.okbutton()
| |
|
| |
| def selectdir(self):
| |
| """Take selected directory from the dirnamebox into the dirname"""
| |
| cs=self.component('dirnamebox').curselection()
| |
| if cs!=():
| |
| value=self.component('dirnamebox').get(cs)
| |
| dir=self['directory']
| |
| if not dir:
| |
| dir=os.getcwd()
| |
| if value:
| |
| if value=='..':
| |
| dir=os.path.split(dir)[0]
| |
| else:
| |
| dir=os.path.join(dir,value)
| |
| self.configure(directory=dir)
| |
| self.fillit()
| |
|
| |
| def askfilename(self,directory=None,filter=None):
| |
| """The actual client function. Activates the dialog, and
| |
| returns only after a valid filename has been entered
| |
| (return value is that filename) or when canceled (return
| |
| value is None)"""
| |
| if directory!=None:
| |
| self.configure(directory=directory)
| |
| if filter!=None:
| |
| self.configure(filter=filter)
| |
| self.fillit()
| |
| self.canceled=1 # Needed for when user kills dialog window
| |
| self.activate()
| |
| if self.canceled:
| |
| return None
| |
| else:
| |
| return self.component('filename').get()
| |
|
| |
| lastdir=""
| |
| lastfilter=None
| |
| lasttime=0
| |
| def fillit(self):
| |
| """Get the directory list and show it in the two listboxes"""
| |
| # Do not run unnecesarily
| |
| if self.lastdir==self['directory'] and self.lastfilter==self['filter'] and self.lasttime>os.stat(self.lastdir)[8]:
| |
| return
| |
| self.lastdir=self['directory']
| |
| self.lastfilter=self['filter']
| |
| self.lasttime=time.time()
| |
| dir=self['directory']
| |
| if not dir:
| |
| dir=os.getcwd()
| |
| dirs=['..']
| |
| files=[]
| |
| try:
| |
| fl=os.listdir(dir)
| |
| fl.sort()
| |
| except os.error,arg:
| |
| if arg[0] in (2,20):
| |
| return
| |
| raise
| |
| for f in fl:
| |
| if os.path.isdir(os.path.join(dir,f)):
| |
| dirs.append(f)
| |
| else:
| |
| filter=self['filter']
| |
| if not filter:
| |
| filter='*'
| |
| if fnmatch.fnmatch(f,filter):
| |
| files.append(f)
| |
| self.component('filenamebox').setlist(files)
| |
| self.component('dirnamebox').setlist(dirs)
| |
|
| |
| def validate(self,filename):
| |
| """Validation function. Should return 1 if the filename is valid,
| |
| 0 if invalid. May pop up dialogs to tell user why. Especially
| |
| suited to subclasses: i.e. only return 1 if the file does/doesn't
| |
| exist"""
| |
| return 1
| |
|
| |
|
| |
| class PmwExistingFileDialog(PmwFileDialog):
| |
| def filevalidate(self,string):
| |
| if os.path.isfile(string):
| |
| return Pmw.OK
| |
| else:
| |
| return Pmw.PARTIAL
| |
|
| |
| def validate(self,filename):
| |
| if os.path.isfile(filename):
| |
| return 1
| |
| elif os.path.exists(filename):
| |
| _errorpop(self.interior(),"This is not a plain file")
| |
| return 0
| |
| else:
| |
| _errorpop(self.interior(),"Please select an existing file")
| |
| return 0
| |
|
| |
| class FileDialogButtonClassFactory:
| |
| def get(fn,filter='*'):
| |
| """This returns a FileDialogButton class that will
| |
| call the specified function with the resulting file.
| |
| """
| |
| class FileDialogButton(Tkinter.Button):
| |
| # This is just an ordinary button with special colors.
| |
|
| |
| def __init__(self, master=None, cnf={}, **kw):
| |
| '''when we get a file, we call fn(filename)'''
| |
| self.fn = fn
| |
| self.__toggle = 0
| |
| apply(Tkinter.Button.__init__, (self, master, cnf), kw)
| |
| self.configure(command=self.set)
| |
| def set(self):
| |
| fd = PmwFileDialog(self.master,filter=filter)
| |
| fd.title('Please choose a file')
| |
| n=fd.askfilename()
| |
| if n is not None:
| |
| self.fn(n)
| |
| return FileDialogButton
| |
| get = staticmethod(get)
| |
|
| |
| ############################################################
| |
| ############################################################
| |
| ############################################################
| |
| ## ##
| |
| ## PmwGroups ##
| |
| ## ##
| |
| ############################################################
| |
| ############################################################
| |
| ############################################################
| |
| class VisualizationGroup(Pmw.Group):
| |
| def __init__(self,*args,**kwargs):
| |
| my_options = 'visgroup_num'.split()
| |
| for option in my_options:
| |
| # use these options as attributes of this class
| |
| # and remove them from the kwargs dict before
| |
| # passing on to Pmw.Group.__init__().
| |
| setattr(self,option,kwargs.pop(option))
| |
| kwargs['tag_text'] = kwargs['tag_text'] + ' (%s)'%self.visgroup_num
| |
| Pmw.Group.__init__(self,*args,**kwargs)
| |
| self.refresh()
| |
| self.show_ms = False
| |
| self.show_pi = False
| |
| self.show_ni = False
| |
| def refresh(self):
| |
| things_to_kill = 'error_label update_buttonbox mm_group ms_group pi_group ni_group'.split()
| |
| for thing in things_to_kill:
| |
| try:
| |
| getattr(self,thing).destroy()
| |
| #print "destroyed",thing
| |
| except AttributeError:
| |
| #print "couldn't destroy",thing
| |
|
| |
| # note: this attributeerror will also hit if getattr(self,thing) misses.
| |
| # another note: both halves of the if/else make an update_buttonbox.
| |
| # if you rename the one in the top half to something else, you'll cause nasty Pmw errors.
| |
| pass
| |
| if [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:map'] and [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:molecule']:
| |
| self.mm_group = Pmw.Group(self.interior(),tag_text = 'Maps and Molecules')
| |
| self.map = Pmw.OptionMenu(self.mm_group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Map',
| |
| items = [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:map'],
| |
| )
| |
| self.map.pack(padx=4,side=LEFT)
| |
|
| |
| self.molecule = Pmw.OptionMenu(self.mm_group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Molecule',
| |
| items = [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:molecule'],
| |
| )
| |
| self.molecule.pack(padx=4,side=LEFT)
| |
| self.update_buttonbox = Pmw.ButtonBox(self.mm_group.interior(), padx=0)
| |
| self.update_buttonbox.pack(side=LEFT)
| |
| self.update_buttonbox.add('Update',command=self.refresh)
| |
| self.mm_group.pack(fill = 'both', expand = 1, padx = 4, pady = 5, side=TOP)
| |
|
| |
| self.ms_group = Pmw.Group(self.interior(),tag_text='Molecular Surface')
| |
| self.ms_buttonbox = Pmw.ButtonBox(self.ms_group.interior(), padx=0)
| |
| self.ms_buttonbox.pack()
| |
| self.ms_buttonbox.add('Show',command=self.showMolSurface)
| |
| self.ms_buttonbox.add('Hide',command=self.hideMolSurface)
| |
| self.ms_buttonbox.add('Update',command=self.updateMolSurface)
| |
| self.ms_buttonbox.alignbuttons()
| |
| self.surface_solvent = IntVar()
| |
| self.surface_solvent.set(APBSTools2.defaults['surface_solvent'])
| |
| self.sol_checkbutton = Checkbutton(self.ms_group.interior(),
| |
| text = "Solvent accessible surface",
| |
| variable = self.surface_solvent)
| |
| self.sol_checkbutton.pack()
| |
| self.potential_at_sas = IntVar()
| |
| self.potential_at_sas.set(APBSTools2.defaults['potential_at_sas'])
| |
| self.pot_checkbutton = Checkbutton(self.ms_group.interior(),
| |
| text = "Color by potential on sol. acc. surf.",
| |
| variable = self.potential_at_sas)
| |
| self.pot_checkbutton.pack()
| |
| self.mol_surf_low = Pmw.Counter(self.ms_group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Low',
| |
| orient = 'vertical',
| |
| entry_width = 4,
| |
| entryfield_value = -1,
| |
| datatype = 'real',
| |
| entryfield_validate = {'validator' : 'real'},
| |
| )
| |
| self.mol_surf_middle = Pmw.Counter(self.ms_group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Middle',
| |
| orient = 'vertical',
| |
| entry_width = 4,
| |
| entryfield_value = 0,
| |
| datatype = 'real',
| |
| entryfield_validate = {'validator' : 'real'}
| |
| )
| |
| self.mol_surf_high = Pmw.Counter(self.ms_group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'High',
| |
| orient = 'vertical',
| |
| entry_width = 4,
| |
| entryfield_value = 1,
| |
| datatype = 'real',
| |
| entryfield_validate = {'validator' : 'real'}
| |
| )
| |
| bars = (self.mol_surf_low,self.mol_surf_middle,self.mol_surf_high)
| |
| Pmw.alignlabels(bars)
| |
| for bar in bars: bar.pack(side=LEFT)
| |
| self.ms_group.pack(fill = 'both', expand = 1, padx = 4, pady = 5, side=LEFT)
| |
|
| |
| self.pi_group = Pmw.Group(self.interior(),tag_text='Positive Isosurface')
| |
| self.pi_buttonbox = Pmw.ButtonBox(self.pi_group.interior(), padx=0)
| |
| self.pi_buttonbox.pack()
| |
| self.pi_buttonbox.add('Show',command=self.showPosSurface)
| |
| self.pi_buttonbox.add('Hide',command=self.hidePosSurface)
| |
| self.pi_buttonbox.add('Update',command=self.updatePosSurface)
| |
| self.pi_buttonbox.alignbuttons()
| |
| self.pos_surf_val = Pmw.Counter(self.pi_group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Contour (kT/e)',
| |
| orient = 'vertical',
| |
| entry_width = 4,
| |
| entryfield_value = 1,
| |
| datatype = 'real',
| |
| entryfield_validate = {'validator' : 'real', 'min':0}
| |
| )
| |
| self.pos_surf_val.pack(side=LEFT)
| |
| self.pi_group.pack(fill = 'both', expand = 1, padx = 4, pady = 5, side=LEFT)
| |
|
| |
| self.ni_group = Pmw.Group(self.interior(),tag_text='Negative Isosurface')
| |
| self.ni_buttonbox = Pmw.ButtonBox(self.ni_group.interior(), padx=0)
| |
| self.ni_buttonbox.pack()
| |
| self.ni_buttonbox.add('Show',command=self.showNegSurface)
| |
| self.ni_buttonbox.add('Hide',command=self.hideNegSurface)
| |
| self.ni_buttonbox.add('Update',command=self.updateNegSurface)
| |
| self.ni_buttonbox.alignbuttons()
| |
| self.neg_surf_val = Pmw.Counter(self.ni_group.interior(),
| |
| labelpos = 'w',
| |
| label_text = 'Contour (kT/e)',
| |
| orient = 'vertical',
| |
| entry_width = 4,
| |
| entryfield_value = -1,
| |
| datatype = 'real',
| |
| entryfield_validate = {'validator' : 'real', 'max':0}
| |
| )
| |
| self.neg_surf_val.pack(side=LEFT)
| |
| self.ni_group.pack(fill = 'both', expand = 1, padx = 4, pady = 5, side=LEFT)
| |
|
| |
| else:
| |
| self.error_label = Tkinter.Label(self.interior(),
| |
| pady = 10,
| |
| justify=LEFT,
| |
| text = '''You must have at least a molecule and a map loaded.
| |
| If you have a molecule and a map loaded, please click "Update"''',
| |
| )
| |
| self.error_label.pack()
| |
| self.update_buttonbox = Pmw.ButtonBox(self.interior(), padx=0)
| |
| self.update_buttonbox.pack()
| |
| self.update_buttonbox.add('Update',command=self.refresh)
| |
|
| |
| def showMolSurface(self):
| |
| self.updateMolSurface()
| |
|
| |
| def hideMolSurface(self):
| |
| pymol.cmd.hide('surface',self.molecule.getvalue())
| |
|
| |
| def getRampName(self):
| |
| #return 'e_lvl'
| |
| idx = [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:molecule'].index(self.molecule.getvalue())
| |
| return '_'.join(('e_lvl',str(idx),str(self.visgroup_num)))
| |
|
| |
| def getIsoPosName(self):
| |
| idx = [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:map'].index(self.map.getvalue())
| |
| return '_'.join(('iso_pos',str(idx),str(self.visgroup_num)))
| |
|
| |
| def getIsoNegName(self):
| |
| idx = [i for i in pymol.cmd.get_names() if pymol.cmd.get_type(i)=='object:map'].index(self.map.getvalue())
| |
| return '_'.join(('iso_neg',str(idx),str(self.visgroup_num)))
| |
|
| |
| def updateMolSurface(self):
| |
| molecule_name = self.molecule.getvalue()
| |
| ramp_name = self.getRampName()
| |
| map_name = self.map.getvalue()
| |
| low = float(self.mol_surf_low.getvalue())
| |
| mid = float(self.mol_surf_middle.getvalue())
| |
| high = float(self.mol_surf_high.getvalue())
| |
| range = [low,mid,high]
| |
| print " APBS Tools: range is",range
| |
| pymol.cmd.delete(ramp_name)
| |
| pymol.cmd.ramp_new(ramp_name,map_name,range)
| |
| pymol.cmd.set('surface_color',ramp_name,molecule_name)
| |
| if self.surface_solvent.get()==1:
| |
| pymol.cmd.set('surface_solvent',1,molecule_name)
| |
| pymol.cmd.set('surface_ramp_above_mode',0,molecule_name)
| |
| else:
| |
| pymol.cmd.set('surface_solvent',0,molecule_name)
| |
| pymol.cmd.set('surface_ramp_above_mode',self.potential_at_sas.get(),molecule_name)
| |
| pymol.cmd.show('surface',molecule_name)
| |
| pymol.cmd.refresh()
| |
| pymol.cmd.recolor(molecule_name)
| |
|
| |
| def showPosSurface(self):
| |
| self.updatePosSurface()
| |
| def hidePosSurface(self):
| |
| pymol.cmd.hide('everything',self.getIsoPosName())
| |
| def updatePosSurface(self):
| |
| pymol.cmd.delete(self.getIsoPosName())
| |
| pymol.cmd.isosurface(self.getIsoPosName(),self.map.getvalue(),float(self.pos_surf_val.getvalue()))
| |
| pymol.cmd.color('blue',self.getIsoPosName())
| |
| pymol.cmd.show('everything',self.getIsoPosName())
| |
| def showNegSurface(self):
| |
| self.updateNegSurface()
| |
| def hideNegSurface(self):
| |
| pymol.cmd.hide('everything',self.getIsoNegName())
| |
| def updateNegSurface(self):
| |
| pymol.cmd.delete(self.getIsoNegName())
| |
| pymol.cmd.isosurface(self.getIsoNegName(),self.map.getvalue(),float(self.neg_surf_val.getvalue()))
| |
| pymol.cmd.color('red',self.getIsoNegName())
| |
| pymol.cmd.show('everything',self.getIsoNegName())
| |
|
| |
|
| |
| </source>
| |
|
| |
|
| = APBS Plugin FAQ = | | = APBS Plugin FAQ = |