Você está na página 1de 94

Schrdinger Press

Scripting with Python


Scripting with
Python
Schrdinger Suite 2009
Scripting with Python Copyright 2009 Schrdinger, LLC. All rights reserved.
While care has been taken in the preparation of this publication, Schrdinger
assumes no responsibility for errors or omissions, or for damages resulting from
the use of the information contained herein.
Canvas, CombiGlide, ConfGen, Epik, Glide, Impact, Jaguar, Liaison, LigPrep,
Maestro, Phase, Prime, PrimeX, QikProp, QikFit, QikSim, QSite, SiteMap, Strike, and
WaterMap are trademarks of Schrdinger, LLC. Schrdinger and MacroModel are
registered trademarks of Schrdinger, LLC. MCPRO is a trademark of William L.
Jorgensen. Desmond is a trademark of D. E. Shaw Research. Desmond is used with
the permission of D. E. Shaw Research. All rights reserved. This publication may
contain the trademarks of other companies.
Schrdinger software includes software and libraries provided by third parties. For
details of the copyrights, and terms and conditions associated with such included
third party software, see the Legal Notices for Third-Party Software in your product
installation at $SCHRODINGER/docs/html/third_party_legal.html (Linux OS) or
%SCHRODINGER%\docs\html\third_party_legal.html (Windows OS).
This publication may refer to other third party software not included in or with
Schrdinger software ("such other third party software"), and provide links to third
party Web sites ("linked sites"). References to such other third party software or
linked sites do not constitute an endorsement by Schrdinger, LLC. Use of such
other third party software and linked sites may be subject to third party license
agreements and fees. Schrdinger, LLC and its affiliates have no responsibility or
liability, directly or indirectly, for such other third party software and linked sites,
or for damage resulting from the use thereof. Any warranties that we make
regarding Schrdinger products and services do not apply to such other third party
software or linked sites, or to the interaction between, or interoperability of,
Schrdinger products and services and such other third party software.
Revision A, October 2009
Scripting with Python iii
Contents
Document Conventions.................................................................................................... vii
Chapter 1: Introduction....................................................................................................... 1
Chapter 2: About Python................................................................................................... 3
2.1 What is Python? ........................................................................................................ 3
2.2 Where Can I Find Out More About Python?......................................................... 3
2.3 Some Useful Things to Know About the Python Language.............................. 4
2.4 Why Python?.............................................................................................................. 5
2.5 Isn't It Too Slow?....................................................................................................... 6
Chapter 3: Running Python Within Maestro........................................................ 7
3.1 What Can I Do With Python in Maestro?............................................................... 7
3.2 Basic Concepts.......................................................................................................... 7
3.3 A First Python Script in Maestro ............................................................................ 8
3.4 Scripts, Modules, and Functions............................................................................ 9
3.5 The pythonrun Command........................................................................................ 9
3.6 What To Do If It Doesn't Work ............................................................................... 10
3.7 The pythonimport Command................................................................................ 10
3.8 Adding a Parameter ................................................................................................ 11
3.9 Module Search Path................................................................................................ 12
3.10 The pythoneval Command................................................................................... 12
Chapter 4: Issuing Maestro Commands............................................................... 15
4.1 The maestro Python Module ................................................................................. 15
4.2 Sending a Command to Maestro From a Python Script................................... 16
4.3 Other Ways to Use maestro.command() ............................................................. 17
Contents
Schrdinger Suite 2009 iv
Chapter 5: Manipulating the Workspace.............................................................. 21
5.1 The Structure Concept ........................................................................................... 21
5.2 Getting the Workspace Structure......................................................................... 21
5.3 Setting the Workspace Structure ......................................................................... 22
5.4 Operations on Structures ...................................................................................... 22
5.4.1 Obtaining Information on Atoms ....................................................................... 22
5.4.2 Obtaining Information on Bonds ....................................................................... 24
5.4.3 Adding and Deleting Bonds .............................................................................. 25
5.4.4 Measuring and Adjusting .................................................................................. 25
5.4.5 Deleting Atoms.................................................................................................. 26
5.4.6 Other operations ............................................................................................... 26
5.5 Iterating Over Objects in the Structure ............................................................... 27
5.6 Things You Can Do with the Workspace Structure........................................... 27
Chapter 6: Scripting the Project Table................................................................... 33
6.1 Getting Information About the Project Table...................................................... 33
6.2 Selecting Entries in the Project Table ................................................................. 35
6.3 Working on All Entries in the Project Table........................................................ 37
6.4 Adding New Columns to the Project Table......................................................... 38
Chapter 7: Running Jobs from Scripts................................................................... 41
7.1 Running Jobs From Within Maestro.................................................................... 41
7.2 The maestro.job_wait Function............................................................................ 41
7.3 Customizing Job Incorporation............................................................................ 42
7.3.1 Specifying a Special Job Disposition ................................................................ 43
7.3.2 Incorporating Results Using Your Specialized Incorporation Function ............. 43
7.3.3 Removing Your Job Incorporation Callback ...................................................... 44
7.4 Running and Managing Jobs Outside Maestro ................................................. 44
7.4.1 Access to the Job Database ............................................................................. 44
7.4.2 Information on Job Hosts.................................................................................. 45
Contents
Scripting with Python v
7.4.3 Running Jobs From Python............................................................................... 46
Chapter 8: Writing Your Own Panels ...................................................................... 47
8.1 Tkinter ....................................................................................................................... 47
8.2 Important Considerations...................................................................................... 47
8.3 Supporting Atom Selection from the Workspace.............................................. 48
8.4 Creating Panels with a Maestro Look and Feel ................................................. 50
8.5 Adding a Help Topic to a Panel............................................................................. 51
Chapter 9: Registering Python Functions with Maestro............................ 53
9.1 Periodic Functions.................................................................................................. 53
9.2 Mouse Hover Functions......................................................................................... 54
9.3 Workspace Drawing and Changed Callbacks.................................................... 55
Chapter 10: Debugging Your Scripts....................................................................... 57
10.1 The Power of print................................................................................................. 57
10.2 The pdb Module..................................................................................................... 57
Chapter 11: The Maestro Scripts Menu................................................................ 59
11.1 The scripts.mnu File............................................................................................. 59
11.2 Cascading Menus.................................................................................................. 59
11.3 Creating Scripts to be Installed in Maestro...................................................... 60
Chapter 12: Tips and Traps........................................................................................... 63
12.1 Things to Watch Out For...................................................................................... 63
12.2 Things That Might be Useful ............................................................................... 63
Chapter 13: Running Scripts Outside Maestro................................................ 65
13.1 Running Your Scripts ........................................................................................... 65
Contents
Schrdinger Suite 2009 vi
13.2 Simple Filters ......................................................................................................... 66
Appendix A: Reference Modules............................................................................... 69
Appendix B: The MacroModel Python Package ............................................. 71
B.1 The ComUtil Class ................................................................................................. 71
B.2 The CluUtil Class ................................................................................................... 77
B.3 The apps Module ................................................................................................... 78
Getting Help ............................................................................................................................. 81
Scripting with Python vii
Document Conventions
In addition to the use of italics for names of documents, the font conventions that are used in
this document are summarized in the table below.
Links to other locations in the current document or to other PDF documents are colored like
this: Document Conventions.
In descriptions of command syntax, the following UNIX conventions are used: braces { }
enclose a choice of required items, square brackets [ ] enclose optional items, and the bar
symbol | separates items in a list from which one item must be chosen. Lines of command
syntax that wrap should be interpreted as a single command.
File name, path, and environment variable syntax is generally given with the UNIX conven-
tions. To obtain the Windows conventions, replace the forward slash / with the backslash \ in
path or directory names, and replace the $ at the beginning of an environment variable with a
% at each end. For example, $SCHRODINGER/maestro becomes %SCHRODINGER%\maestro.
In this document, to type text means to type the required text in the specied location, and to
enter text means to type the required text, then press the ENTER key.
References to literature sources are given in square brackets, like this: [10].
Font Example Use
Sans serif Project Table Names of GUI features, such as panels, menus,
menu items, buttons, and labels
Monospace $SCHRODINGER/maestro File names, directory names, commands, envi-
ronment variables, and screen output
Italic lename Text that the user must replace with a value
Sans serif
uppercase
CTRL+H Keyboard keys
Schrdinger Suite 2009 viii
Chapter 1
Scripting with Python 1
Schrdinger Suite Scripting with Python
Chapter 1: Introduction
Since the beginning, Maestro has had a command language. However, until recently, scripting
abilities have been limited to simple lists of Maestro commands. Feedback from users has
shown us that many people need abilities well beyond that. For this reason Schrdinger
provides improved scripting ability with the well-known scripting language Python. The
combination of Python, the Maestro command language, and Python functions for using
Maestro functionality, is very powerful and greatly expands the capability for automating and
customizing Maestro.
On top of the Maestro interface, the Python tools provided with Schrdingers software include
interfaces to the Job Control facility. With these interfaces, scripting capabilities can be
extended into automated workows that combine Schrdingers products in ways that suit the
users needs.
Python is easy to use and fun to learn. It is a straightforward language that doesnt require the
kind of learning curve normally associated with a programming language.
This document aims to provide a non-technical introduction to using Python within Maestro.
There are lots of examples, and a brief description of the most important things you need to
know about Python is included. While a detailed description of how to program in Python is
beyond the scope of this document, that information is readily available elsewhere.
Class and function documentation for Schrdinger modules is present only in the HTML
Python API documentation, which you can open from the HTML documentation index at
$SCHRODINGER/docs/Suite_2009_Index.html. See the HTML API documentation for
questions about specic functionality not covered in this tutorial. You can also open the API
documentation from Maestro, by choosing Python API from the Help menu.
Python 2.6 is included with the Schrdinger software distribution in mmshare. Some of the
examples in this manual run Python interactively, which you can do with this version by
entering the command:
$SCHRODINGER/run python
Note: The following applies if you want to use PyQt: Users of this application may not
make use of the Qt software or functionality provided by this application to develop
software unless the user has purchased a Qt Commercial License from Trolltech, its
successors in interest, or one of its authorized distributors or resellers. User is speci-
cally prohibited from using the Qt Open Source Edition with this Application.
Schrdinger Suite 2009 2
Chapter 2
Scripting with Python 3
Schrdinger Suite Scripting with Python
Chapter 2: About Python
2.1 What is Python?
Python is a feature-rich scripting language that has gained broad acceptance in a wide range of
applications. Unlike programming languages such as C, C++ or Fortran (the languages used to
develop other Schrdinger software like Maestro itself) Python is what is known as an inter-
preted language. This means that it doesn't have to undergo an extensive compilation process
before it can be used. Developing scripts in Python is fast and easy. All the examples given in
this document are fairly short and deliberately avoid advanced language features. However, all
Python language features are available from within Maestro including the use of nearly all of
the hundreds of third party modules available for Python.
What makes Python so valuable for us is that it is both embeddable and extensible. We have
embedded Python in Maestro so that it can provide scripting facilities to control the program.
At the same time we have also extended Python by providing access to a whole range of
Maestro functionality for dealing with chemical structures, Maestro les, and projects.
2.2 Where Can I Find Out More About Python?
There are a number of excellent sources of information about Python, both online and print
materials. Here are a few:
www.python.org contains documentation, examples and a great many interesting links.
Nearly everything you read about Python on this and related web sites will be relevant to
your use of Python in Maestro. Schrdinger Suite 2009 uses Python 2.4.3 so all the
Python language features of that version are available from within Maestro.
If you have some experience with scripting or programming but not with Python, Dive
into Python is lled with valuable, graduated examples that will help you master Python.
If you are a more experienced user, Thinking in Python covers more advanced concepts
like applying design patterns to Python.
O'Reilly has published a number of popular Python books.
The Vaults of Parnassus contain many useful Python modules and examples.
Chapter 2: About Python
Schrdinger Suite 2009 4
2.3 Some Useful Things to Know About the Python
Language
This section is targeted at those who do not have the time to fully master Python but still want
to write (or modify existing) scripts. It focuses on the basic core of Python, just the bare essen-
tials with which to get started.
Indentation matters in Python. Unlike other scripting and programming languages which use
{} to group statements together, statements in Python are grouped simply by the level to which
they are indented relative to one another. This means you need to take care in order to ensure
the indentation reects the logic you intend. Consider the following two examples:
# Example 1:
x=5
y=9
if x > 5 :
x = x-1
x = y+1
print x
This example prints 10 because the line x=y+1 is not part of the if block.
# Example 2:
x=5
y=9
if x > 5 :
x = x-1
x = y+1
print x
This second example prints 5, since the lines x=x-1 and x=y+1 are executed if and only if x is
greater than 5. All Python scripts use indentation to indicate grouping of statements, and it is
usually considered good form to place each Python statement on its own line.
Note: You can use either space characters or tabs for indents, but you should not mix them.
We recommend using spaces.
The # character is used for comments. Comments begin with a # and extend to the end of the
current line. The Python interpreter ignores comments.
The keyword def is used to dene functions, which are groups of Python statements called to
perform a particular task. Function parameters may have default values. For example:
Chapter 2: About Python
Scripting with Python 5
# Example 3
def myfunc( x, y=10 ):
x = x + y
print x
myfunc( 5 )
myfunc( 5, 5 )
Here we have dened a function called myfunc(). It takes two arguments, x and y where y
has a default value of 10. This means you can call myfunc in two ways as shown in this
example. In the rst call to myfunc() a value for x is supplied, but no value for y, so the
default value for y is used. As a result myfunc computes the sum of 5 and 10 and prints the
result which is 15. In the second use, values are supplied for both x and y. By providing an
explicit value for y, the default value is overridden and the result is the sum of 5 and 5 which is
10.
Variables do not need to be explicitly typed or destroyed. In the above examples, the types
(integer, string, real number) of the variables x and y are dened only by the context and do not
need to be declared before the variable is used. Also, unlike other languages such as C and
C++, there is no need to allocate or free memory in Pythonthis is handled automatically.
All Python script les should have a .py sufx. Without this sufx, Maestro does not recog-
nize the les as Python scripts.
2.4 Why Python?
Python is not the only embeddable and extensible scripting language available. Ruby, Tcl and
Perl are all other possibilities. Perl is probably the most serious other contender. In many cases
a preference for a given language is a personal matter, that depends on the user's experience
and personal style. However, given that it is technically possible to use Perl in the same way we
use Python, and that in terms of language features essentially the same sorts of things are
possible with either, there were three reasons we chose Python instead of Perl:
1. While Perl is used widely for system administration and web programming, Python is
more popular in scientic programming and larger scale development. Python is very
scalable: it can be used to write simple scripts or to develop full-edged applications.
2. Of the Maestro users surveyed, most expressed either a strong preference for Python over
Perl, or no preference at all.
3. Python has a clean, straightforward syntax; a benet for new or occasional users.
Chapter 2: About Python
Schrdinger Suite 2009 6
In language comparisons (such as between Python and Perl), there really is no right answer.
However, while you may nd some aspects of Python a little odd at rst, we urge you to
persist. Python is easy to learn and easy to use.
There are a number of accounts available of programmers who have made the switch from Perl
to Python. One of the best is the Why Python? essay, by well-known programmer and author
Eric S. Raymond.
2.5 Isn't It Too Slow?
One of the limitations of an interpreted language like Python is that because each line needs to
be parsed and understood (interpreted) at the time the script is run, it tends to be slow in
comparison to compiled languages like C, which are translated into a low-level machine
description before running.
However, one important point about the way we use Python, both in Maestro and outside of it,
is that much of the heavyweight computation and manipulation of chemical structures is not
actually done in Python. As you will see from the examples in this document, Python in
Maestro is primarily used for controlling the program. The real work is actually done by
Maestro itself. The time and overhead required to interpret a Python script is generally insig-
nicant relative to the work done by Maestro to execute the commands sent to it from a Python
script.
Chapter 3
Scripting with Python 7
Schrdinger Suite Scripting with Python
Chapter 3: Running Python Within Maestro
3.1 What Can I Do With Python in Maestro?
There are two main ways that Python scripts can interact with Maestro: issue Maestro
commands and manipulate Workspace structures and Project Table entries. It is important to
realize that, although Python is the scripting language for Maestro, there is no change to the
command language. The syntax of Maestro commands remains the same. However, what has
changed is the ability to issue Maestro commands from Python, a feature that greatly increases
the utility of these commands. Python scripts can contain control structures (if, while, for, etc.),
variables and parameters (values supplied by the user when the script is run), so now it is
possible to write scripts that are considerably more exible and general than the simple lists of
Maestro commands previously available.
While issuing commands with Python scripts is an extremely powerful mechanism for control-
ling Maestro, it is essentially a one-way communication. There is no way for the scripts to
receive information about Maestro, the structure in the Workspace or entries in the Project
Table. Therefore we have introduced an additional mechanism so Python scripts can directly
manipulate structures and entries, right down to the level of changing the properties of indi-
vidual atoms. In practice many Python scripts use a combination of these two approaches.
3.2 Basic Concepts
In order to effectively write scripts that control Maestro a basic understanding of Maestro
concepts is needed. The two most important concepts are the Project Table and the Workspace.
A Maestro project is a collection of associated data and the Project Table is the way in which
this data is viewed and modied. The Project Table contains zero or more rows. Each row is
often referred to as an entry and consists of a structure (a collection of atoms) and zero or more
properties, which appear as columns in the table. Each column in the Project Table corresponds
to a different property. Acceptable property types are: Boolean, integer, oating point, and
string. Properties are most commonly produced from computational jobs but can also be gener-
ated by Maestro or added manually by users.
The Workspace is the 3D display area in the center of the main window, where molecular
structures are displayed. All 3D display is done in this area. This includes displaying the
molecular structure as well as other information, including labels, measurements, ribbons,
markers, and surfaces. You can include (load) multiple entries simultaneously into the Work-
Chapter 3: Running Python Within Maestro
Schrdinger Suite 2009 8
space for 3D viewing, analysis, or modication. Entries loaded into the Workspace contain
only their structural information. Their properties are not loaded into the Workspace and there-
fore the properties are not accessible via the Workspace structures.
It is also important to understand that entries (structures) that have been modied in the Work-
space are not immediately updated back into the project. By default, this happens when the
entry is implicitly or explicitly excluded from the Workspace. Thus, when writing Python
scripts in which you manipulate the entries in the Workspace but you want to take the struc-
tural entry information from the project, you need to ensure that the Workspace changes have
been synchronized back into the project prior to getting information from the Project Table.
This also applies to cases where you simply want to get the structural information for an entry
in the Project Table: rst make sure that the structural information in the Workspace has been
synchronized back into the project. For more information on how to modify projects see
Chapter 6.
When entry properties are edited in the Project Table they are immediately updated in the
project. This contrasts with the mechanism for updating the Workspaces structural data for an
entry which, as mentioned above, does so at the point at which the entry is excluded from the
Workspace.
3.3 A First Python Script in Maestro
This tutorial starts with a simple script that illustrates the basic mechanism for creating and
running scripts within Maestro.
You can create your Python scripts with any text editor. Some editors, like Emacs, include
special capabilities for Python such as colorizing keywords, comments, and strings; and main-
taining the correct indentation. Another possibility is the standard Python editor idle, which
you can run with the command $SCHRODINGER/run idle.
Example 1. myrst.py
In your editor, create the following script and name the le myfirst.py:
# myfirst.py
def myfirst():
print "Hello World from Maestro"
Take care to indent the second line. It indicates that print "Hello World from Maestro"
is part of the myfirst() function. Save your script and start Maestro from the directory in
which you saved your script.
Chapter 3: Running Python Within Maestro
Scripting with Python 9
3.4 Scripts, Modules, and Functions
Before we actually run the script in Maestro, it is worth discussing the terminology
surrounding Python scripts. While we will continue to use the term script in fairly loose terms,
technically what you just created is a Python module. Modules are named after the les that
contain them. Since you named your le myfirst.py, the module is called myfirst.
Modules generally contain a number of functions. In this example, our module contains a
single function, also named myfirst(). There is, however, no reason why a function needs to
be named after the module: it can have any name you wish.
It is important to understand the distinction between functions and modules. When you ask
Maestro to run a script it is actually executing a single function inside a module; it does not, in
general, run the entire contents of the module. You can in fact place all the functions you write
into a single le, although this practice is not recommended.
A common practice is to place a set of related functions into a module. Some may not be
designed to be directly called from Maestro. You might, for example, call one function from
Maestro and that function in turn might call other functions in the same module.
We have provided a number of useful functions that you can use as starting points to create
your own. You will see more on this in the next chapter.
3.5 The pythonrun Command
Now it is time to run your script. You saved your script as myfirst.py and started Maestro
from the directory that contains the script. Now, enter the following in the Maestro command
input area:
pythonrun myfirst.myfirst
You should see:
Hello World from Maestro
displayed in the terminal window from which you started Maestro. Congratulations! You just
wrote and executed your rst Python script from Maestro.
Note: We specied both the module and function as part of the pythonrun command.
In this example, we had direct access to our script by starting Maestro from the directory
containing the script, but this can quickly become restrictive. See Section 3.9 on page 12 for
details on where to store modules.
Chapter 3: Running Python Within Maestro
Schrdinger Suite 2009 10
3.6 What To Do If It Doesn't Work
If the script did not run as you expected, there are a few things you can try. The error message
in Figure 3.1 means that Maestro was not able to locate the myfirst module. Check the
following:
The le is saved and named myfirst.py
The le exists in the directory from which Maestro was started
You correctly typed the command as pythonrun myfirst.myfirst
If you see an error message like Figure 3.2 you probably introduced a syntax error into the
script. For example, this message indicates the indentation was not correct. The second line of
the function must be indented relative to the rst so that Python knows print belongs to the
myfirst function.
3.7 The pythonimport Command
While pythonrun is the most commonly used Maestro command associated with Python
scripting, if you are making frequent changes to a python script you will also nd
pythonimport useful. One of the side effects of using pythonrun is that a copy of the
Figure 3.1. Import Error.
Figure 3.2. Indentation Error.
Chapter 3: Running Python Within Maestro
Scripting with Python 11
module containing the requested script is actually loaded into memory. This allows Maestro to
be more efcient in handling repeated requests for the same script. But if you now make
changes to the myfirst.py le while Maestro is running and once again enter:
pythonrun myfirst.myfirst
you do not see the effects of your changes. Maestro is still using the original myfirst script
from the previously loaded myfirst.py le. This is where the pythonimport command
comes into play. When you run:
pythonimport myfirst
Maestro reloads the myfirst.py le so that the next time you execute the script using
pythonrun, the updated version is used.
3.8 Adding a Parameter
A small change to myfirst.py illustrates how to pass information to a Python script in
Maestro.
Example 2. myrst.py
# myfirst.py
def myfirst( param = "" ):
print "Hello World from Maestro " + param
Save your changes and then use pythonimport to reload myfirst.py. Now run the script:
pythonrun myfirst.myfirst
It displays the same output as the rst version of myfirst.py: Hello World from Maestro.
This is because we added an empty string as the default parameter. If you do not supply a value
for param, the script supplies an empty string. If we had not added the default value (param =
""), then running myfirst without a value for the parameter results in an error.
Now run the script with a parameter:
pythonrun myfirst.myfirst "a second time"
You should see:
Hello World from Maestro a second time
This is a very signicant feature of running Python from within Maestro. Unlike older Maestro
command scripts, where everything needed to be hard-coded into the script, Python functions
can take any number of parameters, some or all of which can have default values. This allows
Chapter 3: Running Python Within Maestro
Schrdinger Suite 2009 12
Python scripts to be very general. For example, you can write a script that operates on a le-
name supplied by the user at the time the script is run.
Note: With the exception of quoted strings (""), which are treated as a single parameter, all
parameters entered from the Maestro command input area must be separated by white
space.
3.9 Module Search Path
This section describes how Maestro locates the module le. In our example we made sure that
Maestro was started from the directory containing myfirst.py. This is typical for developing
scripts. However, it is not very convenient when you want to use your script in many different
directories. To make this easier, we created a special directory for your scripts:
your home dir/.schrodinger/maestroversion/scripts
where version is the 2-digit Maestro version number. Inside this directory you can place les
like myfirst.py. Then you can issue commands like:
pythonrun myfirst.myfirst
from any directory in which you run Maestro.
Note: Maestro looks rst in the current directory (the one from which you started Maestro)
rst before looking in $HOME/.schrodinger/maestroversion/scripts. So if you
have a local copy of the script, the local copy is used instead.
3.10 The pythoneval Command
There is a third Python-related Maestro command, pythoneval. This command is used less
frequently than the commands already discussed, but it is described here for completeness.
Pythoneval allows you to execute any Python expression in the Maestro Python interpreter.
This means you have interactive access to the interpreter.
You can achieve the same result as pythonrun but you must remember to rst import the
module and use the Python style syntax to call any functions. So using the example for
myfirst.py as described above:
pythoneval import myfirst
pythoneval myfirst.myfirst("a second time")
is equivalent to:
pythonrun myfirst.myfirst "a second time"
Chapter 3: Running Python Within Maestro
Scripting with Python 13
Now you know the basics of creating Python scripts and running them from within Maestro.
The next chapter describes how to create a Python script that actually interacts with Maestro.
Schrdinger Suite 2009 14
Chapter 4
Scripting with Python 15
Schrdinger Suite Scripting with Python
Chapter 4: Issuing Maestro Commands
The previous chapter showed how to run a very simple Python script from within Maestro and
introduced modules and functions. This chapter discusses how you can write scripts to issue
Maestro commands.
4.1 The maestro Python Module
In order to communicate with Maestro you need to rst import the provided maestro module
into your script. You'll see that most of the example scripts in the remainder of this document
contain a line which looks something like:
from schrodinger.maestro import maestro
near the top. This tells Python to load and make available the functions contained in the
maestro module, which is part of the Schrdinger package of modules.
There are several variants of this. In our examples we use the from schrodinger.maestro
import maestro form. This means that in the example scripts we will always reference the
functions in this module in the fully qualied form as maestro.function(). However, if you
look at Python documentation or other scripts, you will see that there are other ways you can
use the import command. For example:
from schrodinger.maestro.maestro import *
This means that everything in the maestro module can be used directly in your script without
the maestro. prex.
You can even go further and use an import expression such as:
from schrodinger.maestro.maestro import command as c
This means that instead of using maestro.command() you can simply use c().
Note: You can write your own modules and import them into other modules. The only
requirement is that your modules are in the module search path as described in the
previous chapter.
Chapter 4: Issuing Maestro Commands
Schrdinger Suite 2009 16
4.2 Sending a Command to Maestro From a Python
Script
Example 1. roty.py
1. Create a le called roty.py that contains the following:
# roty.py
from schrodinger.maestro import maestro
def roty( by=90 ):
maestro.command( "rotate y=%d" % by )
2. In Maestro, place a structure in the Workspace.
3. In the command input area, enter the following command:
pythonrun roty.roty
You should see the contents of the Workspace rotate by (the default value of) 90 degrees
about the Y axis.
4. You can rotate by any amount by supplying your own value for the parameter. For
instance:
pythonrun roty.roty 30
rotates the contents of the Workspace by 30 degrees.
There are a couple of notable things about this script:
We use maestro.command() to tell Maestro to issue a command. The command is just
a normal Maestro command (and can include any aliases you may have dened for the
command). The hundreds of available commands and their options are documented in the
Maestro Command Reference Manual.
Note: You can review the commands that have been issued in the normal operation of
Maestro by choosing Command Script Editor from the Edit menu.
The maestro.command() function takes a single string parameter. However we can
substitute the value of variables into that string before issuing the command. This is what
the
"rotate y=%d" % by
expression does. The value of by is substituted into the string before the command is
issued. This is an extremely powerful mechanism and we provide more examples later in
this document.
Chapter 4: Issuing Maestro Commands
Scripting with Python 17
There are a couple of enhancements we can make to this script. In the previous example the
axis of rotation is hard coded into the Python function. We could create similar functions called
rotx() and rotz() to rotate around the other axes. Another option is to supply the axis of
rotation as a parameter and add that into the command string before issuing the command.
Here is the reworked example in which we have not only parameterized the axis of rotation but
also taken care to verify that the supplied argument is a valid axis:
# rot.py
from schrodinger.maestro import maestro
def rot( axis="y", by=90 ):
if( axis != "y" and axis != "x" and axis != "z" ):
raise Exception, "%s is not a valid axis" % axis
maestro.command( "rotate %s=%d" % (axis,by) )
Now you can issue a Maestro command such as:
pythonrun rot.rot x 30
to get a rotation of 30 degrees around the X-axis.
Note: While this might be a good example of building your own function that uses parame-
ters, you will probably want to use the Maestro rotate command directly to rotate
structures in the Workspace:
rotate x=30
4.3 Other Ways to Use maestro.command()
There are two other ways in which maestro.command() can be used. First, instead of
providing a single string, it is possible to specify the keyword, operands, and options of the
Maestro command separately. For example, to rotate around the x, y, and z axis use the
following:
maestro.command("rotate", x=5)
maestro.command("rotate", y=5)
maestro.command("rotate", z=5)
In this way the keyword rotate is a separate parameter from the options: x=5, etc.
It is also possible to issue more than one command in a single call to maestro.command() by
using a triple quoted string with each command on a separate line. For example, the commands
above can also be issued as:
Chapter 4: Issuing Maestro Commands
Schrdinger Suite 2009 18
maestro.command("""
rotate x=5
rotate y=5
rotate z=5
""")
This is a useful way to issue a series of Maestro commands taken directly from the Maestro
command script editor. Note that each command must be on a new line.
Example 2. spin.py
Before we nish this introduction we will look at a more sophisticated examplea Python
function that does something not currently possible with a Maestro command. The following
example uses the form of maestro.command() where the options are specied separately
from the keyword:
#spin.py
from schrodinger.maestro import maestro
import time
def spin(axis="Y",step=10,slp=0.1):
total_rotate=0
# Verify the axis:
if axis != "X" and axis != "Y" and axis != "Z" :
raise "MyException", "Can't use axis: " + axis
while( total_rotate < 360.0 ) :
# Issue a rotate command.
if axis == "X":
maestro.command("rotate", x=step)
elif axis == "Y":
maestro.command("rotate", y=step)
elif axis == "Z" :
maestro.command("rotate", z=step)
# Redraw the window
maestro.redraw()
# Increment the total rotation by the step increment:
total_rotate += step
time.sleep(slp)
return
When this is run as:
pythonrun spin.spin Y 20 0.2
Chapter 4: Issuing Maestro Commands
Scripting with Python 19
it spins the structure in the Workspace around the Y axis 360 degrees in increments of 20
degrees. The axis, increment, and the delay are all specied as parameters.
There are a few points to make about this script:
In addition to including the maestro module we also include the standard Python mod-
ule time. This allows us access to the time.sleep() function, used in this script to
introduce a short delay after each rotation.
Note how the total_rotate variable is used in the while loop. You can use any com-
bination of parameters and variables in combination with the functions in the maestro
module.
In this particular function we need to use maestro.redraw() to force the contents of
the Workspace to be redrawn after each rotation.
If you want to experiment with issuing commands from your own scripts, this example is a
good place to start. As an exercise, create a script that rotates the structure rst one way and
then another.
It is also possible to use Maestro's command alias function to create new commands. For
example, if you issue:
alias spin pythonrun spin
then you can just use spin like any other command.
In general, if a task can be performed by issuing a Maestro command, that is the preferred way
to achieve it from a Python script. Not only does this generally result in the shortest possible
script, but Maestro commands also automatically update the internal state of Maestro,
redrawing the Workspace as needed, and so on.
As powerful as these techniques are, there are still things you cannot achieve using Maestro
commands alone. The following chapters describe how to control Maestro at a lower level of
detail.
Schrdinger Suite 2009 20
Chapter 5
Scripting with Python 21
Schrdinger Suite Scripting with Python
Chapter 5: Manipulating the Workspace
Previous chapters covered how to run Python scripts in the Maestro environment and how to
issue commands from those scripts. Important information about some of the basic concepts
important to Python script writers was presented in Section 3.2 on page 7, which you should
read before proceeding if you have not already done so. In this chapter we discuss more
sophisticated and powerful features that allow you to directly manipulate the structure in the
Workspace.
5.1 The Structure Concept
The chapters that follow refer to the concept of a structure. In Maestro, a structure is a collec-
tion of atoms. The contents of the Workspace are considered a structure, as are individual
entries in the Project Table. Maestro stores information about structures: information about the
atoms, bonds, and their properties. Python can get structures and manipulate them using this
stored information. To do this, Python uses the functions in the structure.py module, which
you can import into your script with the following command:
from schrodinger import structure
Once you get a structure, you can manipulate it in many ways, including deleting all the atoms.
5.2 Getting the Workspace Structure
As long as your script is running you can get the structure which corresponds to the contents of
the Workspace. This structure is valid for as long as your script is running. However you
should take care to get the structure again if your script issues a Maestro command that
changes the contents of the Workspace, such as importing new structures or including new
entries. The safest approach is to treat the structure as valid only until the completion of the
next Maestro command.
To get the Workspace structure in a Python script, use a statement such as:
st = maestro.workspace_get()
Chapter 5: Manipulating the Workspace
Schrdinger Suite 2009 22
Once you have a structure there are a number of operations you can perform on it. You should
however note the following:
The structure that is returned from workspace_get() is the actual Workspace structure
as used by Maestro. Any changes made will be reected in the Workspace.
The structure object returned does not contain any properties, such as those associated
with the entry in the Project Table. You have to use the project module to get access to
properties.
If you want to pass the structure to another operation we suggest you make a copy of it
with Structure.copy().
5.3 Setting the Workspace Structure
Once you change the structure, you can pass it back to Maestro for display. To do this, use:
maestro.workspace_set(regenerate_markers=True)
Then you can use:
maestro.redraw_request()
to request that Maestro redraw the contents of the Workspace when your script has nished
executing. You can also use maestro.redraw() to redraw the contents of the Workspace
before your script has nished executing.
Setting regenerate_markers to True (the default) forces Maestro to update markers for
distances, labels, and so on, and to apply any changes to the Workspace structure. It should be
set to True in most circumstances.
Note: workspace_set() will not work correctly if the specied Structure is passed directly
from Project Tables row.structure (or if it is managed by another C library). The
workaround is to pass a copy of the Structure.
5.4 Operations on Structures
The following summarizes many of the operations possible with a structure object.
5.4.1 Obtaining Information on Atoms
You can obtain information on atoms through the atom property of a structure. It is possible to
index individual atoms (indices start from 1) or to iterate over atoms. So the following two
statements are equivalent:
Chapter 5: Manipulating the Workspace
Scripting with Python 23
for iatom in st.atom:
print iatom.x
for iatom in range(1,len(st.atom)+1):
print st.atom[iatom].x
Here x is the x coordinate for the atom, but any of the properties shown in Table 5.1 and
Table 5.2 can be used.
Table 5.1. Atom properties for access or modication.
Property Description
atom_name Maestro atom name (used for Jaguar mostly)
atom_style Molecular representation of the atom (wire, CPK etc.)
atom_type MacroModel atom type
atomic_number Atomic number
chain PDB chain name
color Integer index representing color in Maestro color palette
formal_charge Formal charge
growname Maestro builder grow name
inscode PDB residue insertion code
partial_charge Partial atomic charge
pdbname PDB atom name
pdbres PDB residue name
resnum PDB residue number
secondary_structure Secondary structure assignment (HE-)
solvation_charge Solvation atomic charge
temperature_factor PDB temperature factor (isotropic B factor)
visible Workspace display state
x x coordinate
xyz List of atomic coordinates [x, y, z]
y y coordinate
z z coordinate
Chapter 5: Manipulating the Workspace
Schrdinger Suite 2009 24
Atom properties can also be obtained using the data names as they appear in the Maestro le.
For example the following two ways of printing the x coordinate are equivalent.
for iatom in st.atom:
print iatom.x
for iatom in st.atom:
print iatom.property['r_m_x_coord']
5.4.2 Obtaining Information on Bonds
Once you have an atom, you can obtain information on the bonds associated with that atom by
using the bond property. So for example:
total_order=0
for iatom in st.atom:
for ibond in iatom.bond:
total_order += ibond.order
Table 5.2. Atom properties for access only - cannot be modied.
Property Description
atomic_number Atomic number of the atom.
atomic_weight Atomic weight of the atom. If implicit hydrogens are present, they
are included as part of the atomic weight.
bond_total Total number of bonds to this atom
bonded_atoms An iterator that returns atoms bonded to this atom
chirality Chirality of the atom: R, S, or None.
element Element symbol
entry_id Entry ID
entry_name Formerly entry name, now returns entry ID. Use entry_id
instead. Entry name should be obtained as a property from the
project via s_m_entry_name
index Index (atom number) of the atom in the structure, ignoring any
classication into molecule, entry, and so on.
molecule_number Number of the molecule to which this atom belongs
number_by_entry Atom number by entry
number_by_molecule Atom number by molecule
Chapter 5: Manipulating the Workspace
Scripting with Python 25
This example uses the bond order property. The available bond properties are listed in
Table 5.3.
5.4.3 Adding and Deleting Bonds
This can be done via the structure class:
st.addBond( 12, 17, 2 )
adds (or sets if it already exists) a double bond between atoms 12 and 17.
st.deleteBond( 12, 17 )
deletes the bond between atom 12 and 17.
There is also the areBound() method which returns True if the two atoms specied have a
bond between them.
5.4.4 Measuring and Adjusting
To measure, you can use the measure() method of the structure class:
st = maestro.workspace_get()
print st.measure( 1, 2 ) # Distance between atoms 1 and 2
print st.measure( 1, 2, 3 ) # Bond angle between 1, 2, and 3
print st.measure( 1, 2, 3, 4 ) # Torsion angle between 1, 2, 3, and 4
Note that the structureutil module contains a measure() method, which allows
measurements of any type to be performed between different Structure objects and also
supports determining the angle between two planes (as dened between two sets of three
atoms).
Table 5.3. Bond properties for access or modication.
Property Description
order Bond order
atom1 The rst atom of the bond
atom2 The second atom of the bond
style The molecular representation of the bond (wire, tube)
Chapter 5: Manipulating the Workspace
Schrdinger Suite 2009 26
Adjust works in a similar manner:
st.adjust( 2.5, 1, 3 ) # Set distance between atoms 1 and 2 to 2.5 Angs
st.adjust( 110, 1, 2, 3 ) # Set bond angle between atoms 1, 2, and 3 to 110 degrees
st.adjust( 180.0, 1, 2, 3, 4 )
# Set the torsion angle between atoms 1, 2, 3, and 4 to 180.0 degrees
5.4.5 Deleting Atoms
This is done with the deleteAtoms() method. For example:
to_del = [1,2,5]
st.deleteAtoms(to_del)
5.4.6 Other operations
The structureutil model contains a number of functions which operate on Structure objects.
These include the following
Substructure searching or matching:
Matching a SMARTS expression
Matching a list of SMARTS expressions
Matching a list MacroModel substructure notation expression
Evaluating a Atom Specication Language (ASL) expression
Locating the smallest set of smallest rings
Generating a SMILES expression for a set of atoms in a structure
Generating a SMARTS expression for a set of atoms in a structure
Properties:
Measuring distances, angles, dihedrals and plane angles between structures
Getting a list of chiral atoms
Getting a list of rotatable bonds
Testing if hydrogens are present
Determining if a H-bond criteria is fullled.
Superimposing structures:
Superposition based on lists of atoms
Superposition of conformers
Structure manipulation:
Addition of hydrogens in standard positions
Generation of crystal mate structures
For more detail see the HTML documentation of the structureutil Module.
Chapter 5: Manipulating the Workspace
Scripting with Python 27
5.5 Iterating Over Objects in the Structure
It is possible to iterate over a number of objects in a Structure objectchains, molecules, resi-
dues and rings. These iterators all function in a similar way:
st = maestro.workspace_get()
print "There are %d molecules" % len(st.molecule)
imol=1
for mol in st.molecule:
print "There are %d atoms in the molecule" % len(mol.atom)
for atom in mol.atom:
# Do something for atoms in molecule
molst = mol.extractStructure()
molst.write( "molecule%d.mae" % imol )
imol += 1
See the HTML documentation for the structure module for more information on these iter-
ators. Note that the extractStructure() method provided for the chain, residue, molecule,
and ring objects does not inherit the title or any other structure-level properties of the structure
which it is extracted from.
5.6 Things You Can Do with the Workspace Structure
There are many things you can do with a structure once you retrieve it. We cannot cover all of
them here. For more information, see the HTML documentation for the structure module.
What follows are a couple of examples.
Example 1. closecontact.py
This example illustrates how to issue Maestro commands and manipulate the Maestro Work-
space structure. We use a Python function to highlight close contacts between any atoms sepa-
rated by more than three bonds:
#closecontact.py
from schrodinger.maestro import maestro
from schrodinger import structure
from schrodinger import structureutil
def close_contacts(thresh=2.0) :
# Get the current Workspace structure and calculate the number of atoms:
st = maestro.workspace_get()
distance = 0
# Loop over all the atoms
for iatom in st.atom :
Chapter 5: Manipulating the Workspace
Schrdinger Suite 2009 28
# Calculate a list of all the atoms which are not within three bonds
# of the current "iatom". This is done by evaluating an ASL expression
# "not( withinbonds 3 atom. iatom)"
not_neighbours = structureutil.evaluate_asl( st,
"not( withinbonds 3 atom. %d)" %
int(iatom) )
for jatom in not_neighbours :
# Calculate the iatom-jatom distance
distance = st.measure( iatom, jatom)
if( distance < thresh ) :
# This distance is less than the threshold - generate
# a maestro command:
maestro.command("distance %d %d"% (int(iatom), int(jatom)) )
By now you recognize the import maestro statement. This example also imports two addi-
tional modules, structure and structureutil, that we provide to perform operations at a
lower level.
The rst task in close_contacts() is to get the structure from the Workspace. Next we loop
over all atoms in the structure.
For each atom in the Workspace, we only want to calculate the distance away from the current
atom if it is more than three bonds away. An easy way to calculate this is with an ASL expres-
sion: not( withinbonds 3 atom.iatom).
Evaluating this returns a Python list containing the atoms that satisfy our expression. We use
that list in an inner loop to calculate the distance from the current atom. If a distance is less
than the given threshold, we use Maestro to mark the distance by issuing the distance
command.
This script contains common tasks: looping over all atoms, evaluating ASL expressions, and
making measurements on the structure. Note that since we did not make any changes to the
structure directly, we did not need to call maestro.workspace_set().
Example 2. rotH.py
The following script adds hydrogens to the structure in the Workspace, and attempts to rotate
the O-H and S-H groups on SER, THR, TYR, and CYS residues to place the hydrogen as close
as possible to an acceptor. This is also an example of using multiple functions in a Python
module. Only one of the functions is intended to be called from Maestro. The other simply
improves the readability of the script.
Note: This script is provided purely as an example of how to manipulate the workspaceit is
not intended to be a solution to the difcult problem of orienting hydrogens in
proteins!
Chapter 5: Manipulating the Workspace
Scripting with Python 29
#rotH.py
#Import the modules we need:
from schrodinger.maestro import maestro
from schrodinger import structure
from schrodinger import structureutil
def rotH( radius = 4.0 ):
""" This is the function which is to be called from Maestro. It takes
a single parameter which is for each H-X how far from X we should
look for acceptors (the default is 4.0) """
# Start by getting the workspace structure
st = maestro.workspace_get()
# Add hydrogens to the structure. We could do this by using a Maestro
# command but this shows how we can also do it without using Maestro. After
# we add hydrogens we can then get the number of atoms:
structureutil.add_hydrogens( st )
num_atoms = len(st.atom)
# Now locate all the rotatable atoms in all the CYS, SER, TYR and THR.
# The simplest way to do this is using an ASL expression:
rotables = structureutil.evaluate_asl( st,
"(res.ptype SER, THR, TYR, CYS ) and (atom.ptype HG, HG1, HH )")
# Create a couple of empty lists to hold the numbers of the hydrogen
# atoms which have nearby acceptors and the nearest acceptor for each one:
h_list = []
acc_list = []
# rotables is now a list of the appropriate atoms. We can loop over that
# and do what we need to do with them:
for h in rotables:
# We need to locate a suitable dihedral angle to rotate:
dihedral = get_dihedral_atoms( st, h )
if not len(dihedral) == 4 :
# Under normal circumstances there shouldn't be any situations
# where we can't locate four atoms. However, there is the chance
# that we might get an incomplete residue in a PDB file, so we'll
# just ignore this residue if that's the case:
continue
# We can use another ASL expression to locate all the possible
# acceptors within a reasonable distance of the heavy atom which
# the hydrogen is attached to:
Chapter 5: Manipulating the Workspace
Schrdinger Suite 2009 30
acc_types = "OD1, OE1, OD1, SG, SD, ND1, NE2, OH, O"
asl = "( within %f atom.num %d ) and atom.ptype %s" % ( radius,
dihedral[1],
acc_types)
# Note that we exclude the backbone and the residue we are in:
asl = \
"( %s ) and ( sidechain or res. HOH ) and not fillres( atom.num %d )" \
% ( asl, dihedral[1] )
acceptors = structureutil.evaluate_asl( st, asl )
ang = 0.0
min_dist = 1000.0
best_ang = 0.0
# If it actually found some suitable acceptors, we can
# then scan the C-C-O-H dihedral see which dihedral gives the
# closest contact to an acceptor. The scan is done in increments
# of 5 degrees:
while len(acceptors) > 0 and ang < 360.0 :
# Set to the current angle:
# Note that we pass the dihedral
# as C2-C1-X-H as specifying it in this way indicates
# we want to rotate the hydrogen:
st.adjust( ang, dihedral[3], dihedral[2],
dihedral[1], dihedral[0] )
# For each acceptor atom measure the distance and find out
# whether we've actually found a closer match than we've found
# before:
for acc in acceptors:
dist = st.measure( h, acc )
if dist < min_dist:
min_dist = dist
best_ang = ang
best_acc = acc
# increment the angle by 5 degrees:
ang += 5.0
# We've tried all the angles now. Reset it back to the one
# which gave us the closest contact with an acceptor:
if len(acceptors) > 0:
st.adjust( best_ang, dihedral[3], dihedral[2],
dihedral[1], dihedral[0] )
# Keep a list of the atoms associated with the best
Chapter 5: Manipulating the Workspace
Scripting with Python 31
# interaction. For convenience we keep a string representation
# of the atom number as we know now that we will later
# transform this into an ASL expression:
h_list.append( "%d" % h )
acc_list.append( "%d" % best_acc )
# Finally we tell Maestro that we want this structure to be used back
# in the workspace:
maestro.workspace_set( st )
# Put up some hydrogen bond markers to highlight if we
# have picked up any H-bonds
if( len( h_list ) > 0 ):
h_asl = ", ".join( h_list )
acc_asl = ", ".join( acc_list )
maestro.command( "hbondset1 atom.num %s , %s " % (h_asl, acc_asl) )
return
##########################################################################
def get_dihedral_atoms( st, h ):
""" For atom number h in the structure st, find four atoms to
be used to scan the C-C-X-H dihedral. These are returned as a list.
This function illustrates how to traverse the bonds of a structure """
ret_list = []
# The fist atom will be H itself:
ret_list.append(h)
# Now find the O or S attached to the H. Note that bonds (like everything
# associated with structures) are indexed from "1" so we are
# looking for the first bond:
Xatom = st.atom[h].bond[1].atom2
ret_list.append( int(Xatom) )
# Now find a suitable non-H atom bonded to the X:
C1atom = -1
for b in st.atom[Xatom].bond:
conn_atom = b.atom2
# This is probably the easiest way to find a non-H atom:
if not conn_atom.atomic_number == 1 :
C1atom = int(conn_atom)
ret_list.append( C1atom )
# Leave the loop:
break
Chapter 5: Manipulating the Workspace
Schrdinger Suite 2009 32
# Check to see that we did find a C1 atom:
if C1atom < 0 :
return ret_list
# Now look for the final atom we need:
for b in st.atom[C1atom].bond:
conn_atom = b.atom2
# This is probably the easiest way to find a non-H atom:
if not conn_atom.atomic_number == 1 :
C2atom = int(conn_atom)
ret_list.append( C2atom )
# Leave the loop:
break
return ret_list
Now that we have seen how to manipulate the structure from the Workspace, next we will look
at how to access the Project Table directly.
Chapter 6
Scripting with Python 33
Schrdinger Suite Scripting with Python
Chapter 6: Scripting the Project Table
While using Python scripts to manipulate the structure in the Workspace is useful for extending
the functionality of Maestro, you can also automate Maestro by operating on structures in the
Project Table. This chapter provides an overview of the possibilities. Before proceeding please
read Section 3.2 on page 7 for a description of some important basic concepts.
6.1 Getting Information About the Project Table
Sometimes the easiest way to operate on the Project Table is to bring each structure into the
Workspace in turn and operate on it there by issuing Maestro commands. You can do this with
the maestro.project_table_get() function and looping over all the items in the table.
By default such looping only returns the selected entries. So a loop like:
pt = maestro.project_table_get()
# Loop over the selected entries
for sel_entry in pt:
# Do something for selected entries only using "sel"
only operates on the selected entries whereas:
pt = maestro.project_table_get()
# Loop over the selected entries
for irow in xrange(1,len(pt)+1):
# Do something for all entries using pt[irow]
operates on all entries.
Example 1. saveimage.py
Here is an example that saves a .jpg image for each selected entry:
#saveimage.py
from schrodinger.maestro import maestro
from schrodinger import project
def save_image():
pt = maestro.project_table_get()
Chapter 6: Scripting the Project Table
Schrdinger Suite 2009 34
# Loop over the selected entries
for sel_entry in pt:
eid = pt[sel_entry]['s_m_entry_id']
maestro.command("entrywsincludeonly entry \"%s\"" % eid )
maestro.command("saveimage format=jpeg jpeg_quality=75 %s.jpg" %
eid )
Note: The entry ID needs to be surrounded with quotes in the entrywsincludeonly
command. This ensures that entry names that contain spaces are treated as one name.
If your project synchronization preferences are set to Automatic, each time you initiate an
entrywsincludeonly on one entry in the Workspace, all entries in the project are updated.
(To set these preferences, choose Preferences from the Maestro menu, then select the Project
folder.) You can use this to make a change to all the selected entries.
Example 2. meth.py
The following script methylates amides in every selected structure by combining Maestro
commands with direct manipulation of the Workspace structure for each selected entry:
#methylate.py
from schrodinger.maestro import maestro
from schrodinger import structureutil
from schrodinger import project
def methylate():
pt = maestro.project_table_get()
maestro.command("fragment organic Methyl")
for sel_entry in pt:
eid = pt[sel_entry]['s_m_entry_name']
maestro.command("entrywsincludeonly entry", eid )
ct = maestro.workspace_get()
amides = structureutil.evaluate_smarts( ct, "[H]NC(=O)" )
for amide in amides:
maestro.command("attach %d" % amide[0] )
You can use practically any combination of Maestro commands and direct manipulations in the
Workspace structure to achieve the results you want. We have also provided a similar function,
project.getPropertyNames() that returns the property names.
Chapter 6: Scripting the Project Table
Scripting with Python 35
6.2 Selecting Entries in the Project Table
Maestro has built-in support for selecting entries with entryselectonly and similar
commands. This support is provided in three ways:
Entry Selection dialog box
ability to dene lters
use of ESL (see below)
There are limits to what type of selections can be generated with these features. They all rely
on Maestro's Entry Selection Language (ESL). The ESL was designed to work on the proper-
ties associated with entries. For example:
entryselectonly property1 < 4
selects only the entries where property1 has a value less than 4. However, since calculations
are not possible in ESL, the following command would not work:
entryselectonly (2 * property1) < 4
While it is possible to create expressions of arbitrary complexity with the ESL, it is not
possible to make selections in Maestro based on calculations performed on the actual structure
(number of atoms etc.) nor to make selections based on functions of the entry properties such
as the difference between two properties.
If your Python script needs to make selections in the Project Table that are not possible by
issuing a entryselectonly command, the preferred method is a selection lter and the
project.selectRows() function. To do this, write a simple Python function that is called
for every entry in the project. If your function returns True the entry is selected, if it returns
False the entry is not selected. Your function should accept two parameters: the CT corre-
sponding to the current entry and a Python dictionary with an entry for each property in the
Project Table. Note that its also possible to use project.selectRows() with a list of row
numbers to be selected. The following example demonstrates both these approaches:
Example 3. selring.py
This example selects entries that contain rings of a specied size:
#select_ring.py
from schrodinger.maestro import maestro
from schrodinger import structureutil
from schrodinger import project
def select_ring( ring_size ):
Chapter 6: Scripting the Project Table
Schrdinger Suite 2009 36
pt = maestro.project_table_get()
matches = []
# Loop over all the entries in the project
for row in xrange(1,len(pt)+1):
rings = structureutil.find_rings(pt[row].structure)
for ring in rings:
if( len(ring) == ring_size ):
matches.append(row)
# Replacing them all through one call is quicker
# than calling this method over and over
pt.selectRows(project.REPLACE, rows=matches)
# The following two functions show how to select using a callback function
def select_ring2( ring_size ):
pt = maestro.project_table_get()
pt.selectRows(project.REPLACE, ring_size, function=myfunc)
def myfunc(project, ct, property_dict, *args):
"""
Example callback function to select based on a property
Return True if it should be selected
Return False if it should be deselected
"""
ring_size = args[0]
rings = structureutil.find_rings(ct)
for ring in rings:
if( len(ring) == ring_size ):
return True
return False
If you call this function from Maestro as:
pythonrun select_ring.select_ring 4
only those entries in the project with four-membered rings are selected.
Example 4. selprop.py
This example selects entries from the project based on a combination of the entry's structure
and properties:. In this case we use the property dictionary to nd the value of the property we
are interested in.
Chapter 6: Scripting the Project Table
Scripting with Python 37
#selprop.py
from schrodinger.maestro import maestro
from schrodinger import structureutil
from schrodinger import project
def select_proerty( ring_size ):
pt = maestro.project_table_get()
matches = []
# Loop over all the entries in the project
for row in xrange(1,len(pt)+1):
num_atoms = pt[row].structure.atom_total
stars = pt[row]['#stars']
if( num_atoms < 40 and stars != None and stars > 4 ):
matches.append(row)
# Replacing them all through one call is quicker
# than calling this method over and over. So pass in the list
# we built.
pt.selectRows(project.REPLACE, rows=matches)
6.3 Working on All Entries in the Project Table
As shown above, looping over the entries can be used to bring each entry into the Workspace
sequentially and operate on it there. While this is a useful technique, there may be times when
this is not required, or where it would be inefcient to bring all entries into the Workspace. An
alternative is to loop over all entries in the project table and operate on their structures directly.
Example 5. color_by_energy_gradient.py
Here is an example that sets the color of each entry, based on the relative molecular mechanics
energy
Note: Because we return True from the function, the entry structure will be updated in the
Project Table
#color_by_energy_gradient.py
from schrodinger.maestro import maestro
from schrodinger import structureutil
from schrodinger import project
def color_relative():
"""
Chapter 6: Scripting the Project Table
Schrdinger Suite 2009 38
Use the property Relative_Potential_Energy-OPLS-2005 to color all entries
in the project by the property. Leaves entries without this property
alone.
"""
pt = maestro.project_table_get()
for row in xrange(1, len(pt)+1):
# Check to see we actually have the property for this
# entry - if not, go to the next one.
rel_energy = pt[row]['r_mmod_Relative_Potential_Energy-OPLS-2005']
if rel_energy == None:
print "Skipping entry %s since it has no value" % \
pt[row]['s_m_entry_name']
continue
else:
# Color values are defined in $SCHRODINGER/mmshare-vXX/data/colors.res
col = 16 # red
if rel_energy < 4.0:
col = 4 # blue
elif rel_energy < 8.0:
col = 10 # green
elif rel_energy < 12.0:
col = 14 # orange
num_atoms = pt[row].structure.atom_total
ct = pt[row].structure
for i in range(1, num_atoms+1):
ct.atom[i].color = col
6.4 Adding New Columns to the Project Table
The previous example showed how you can loop over each entry in the project table and
modify the structure. It is also possible to add new properties to the Project Table. To do this,
simply add a new value to the property dictionary and make sure your function returns True.
Example 6. count_ch.py
The following example adds properties for the number of hydrogens and carbons to every entry
in the project.
#count_ch.py
from schrodinger.maestro import maestro
from schrodinger import project
Chapter 6: Scripting the Project Table
Scripting with Python 39
def count_ch( ):
pt = maestro.project_table_get()
matches = []
for row in xrange(1, len(pt)+1):
ct = pt[row].structure
num_h_atoms = 0
num_c_atoms = 0
for a in ct.atom:
if a.atomic_number == 1:
num_h_atoms += 1
elif a.atomic_number == 6:
num_c_atoms += 1
# Add or overwrite if already present
# Format for name is: <type>_<author>_<property_name>
# type can be i (integer), r (real), b (boolean), s (string)
# author is "m" for maestro, "user" for user, etc.
# property_name is any text. Underscores are allowed.
pt[row]['i_user_Num_Carbons'] = num_c_atoms
pt[row]['i_user_Num_Hydrogens'] = num_h_atoms
pt.refreshTable()
Example 7. supersel.py
This is another example of looping over all entries. In this case an operation (superposition) is
performed on the entries and the RMS deviation is added as a property in the Project Table.
#supersel.py
from schrodinger.maestro import maestro
from schrodinger import structureutil
from schrodinger import project
def superimpose_select():
pt = maestro.project_table_get()
matches = []
# Ensure superposition can be done
if pt.getSelectedRowTotal() < 2:
return
count = 1
for sel_entry in pt:
if count == 1:
Chapter 6: Scripting the Project Table
Schrdinger Suite 2009 40
# First selected entry is the reference
ref_entry = pt[sel_entry].structure
num_atoms_ref = ref_entry.atom_total
pt[sel_entry]['r_user_MyRMS'] = 0.0
else:
# For all others - superimpose non-hydrogen atoms
ct = pt[sel_entry].structure
num_atoms = pt[sel_entry].structure.atom_total
if not num_atoms == num_atoms_ref :
raise Exception, \
"There must be the same number of atoms in each structure"
super_list = structureutil.evaluate_asl( ct, "not atom.ele H" )
rms = structureutil.superimpose( ref_entry, super_list,
ct, super_list )
pt[sel_entry]['r_user_MyRMS'] = rms
count = count + 1
# Update the project table so users can see the added or
# updated property column
pt.refreshTable()
Chapter 7
Scripting with Python 41
Schrdinger Suite Scripting with Python
Chapter 7: Running Jobs from Scripts
7.1 Running Jobs From Within Maestro
We have yet to provide an example of running a job from a Python script. It is in fact quite
easy, either inside or outside Maestro. From inside maestro, the script needs to simply issue the
appropriate Maestro commands coupled with the maestro.job_wait function.
7.2 The maestro.job_wait Function
One limitation of Maestro command scripts (which are essentially just lists of Maestro
commands) is that it is not possible to write a script that runs a job and waits for it to nish.
This is easily overcome with a Python script and the maestro.job_wait() function. This
example uses the glob module to process all PDB les in the current working directory.
However, it could have just as easily processed all the entries in a project as we saw earlier. The
script redraws the Workspace from time to time to display the current state of the process.
Example 1. allles.py
# allfiles.py
from schrodinger.maestro import maestro
from schrodinger import structureutil
import commands
import glob
import os
# This is the one that should be executed from Maestro. It uses the
# glob.glob subroutine to apply the action to all PDB files:
def mini_all_pdb() :
# first clean up by removing any existing files:
commands.getoutput( "rm *-min.pdb" )
directory=os.getcwd()
path = os.path.join(directory,"*.pdb")
filelist = glob.glob( path )
for afile in filelist:
mini_pdb( afile )
# The function called for every PDB file:
def mini_pdb(file) :
import os
#Convert the filename into a PDB code:
Chapter 7: Running Jobs from Scripts
Schrdinger Suite 2009 42
( path, fname ) = os.path.split( file )
( pdb_code, suffix ) = os.path.splitext( fname )
#Import the PDB file:
maestro.command("entryimport format=pdb %s" % file )
# Delete all molecules < 100 atoms and add hydrogens:
maestro.command("""
delete atom mol.atom < 100
hydrogenapply all
""" )
# Set up the MacroModel job, in vacuo, OPLSA2001, constrained CAs,
# and 100 iterations of LBFGS
maestro.command( """
potential field=oplsaa
potential cutoff=normal
constrainedset atom.ptype " CA "
energytask mini
minienergy method=lbfgs maxiter=100
jobsettings mmod incorporate=replaceentries jobname=%s
""" % pdb_code )
maestro.redraw()
# Run and wait for the job:
maestro.command("energystart")
maestro.job_wait(True)
maestro.command( "jobcleanup files=jobandmonitor %s "% pdb_code )
maestro.redraw()
#The job is now finished - export the structure to a new PDB file
out_file = pdb_code + "-min.pdb"
maestro.command("entryexport format=pdb source=selected %s" % out_file )
# Delete the entry from the project
maestro.command("entrydelete")
7.3 Customizing Job Incorporation
When a job nishes and has output that is incorporatable, Maestro attempts to incorporate the
results into its project. Exactly what Maestro does when incorporating depends on the specic
task that was run. For each task Maestro has a specic rule it follows when incorporating. In
many cases it just applies its standard rule to the generated data.
If you have a task or workow that you have written and you do not want Maestro to apply its
standard job incorporation rules, you can register your own job incorporation callback func-
tion.
Chapter 7: Running Jobs from Scripts
Scripting with Python 43
7.3.1 Specifying a Special Job Disposition
To enable your specialized job incorporation callback function to recognize your specialized
job, you may specify a job disposition that is not used by Schrdinger software (or any other
application). You specify this value when launching the job. Common Schrdinger disposition
values are:
append
appendungrouped
addtoentry_
replace
These values should be avoided if you want your job to receive special handling by your
customized job incorporation function. The addtoentry_ disposition is a prex. Any value
that starts with this string should be avoided. This disposition value tells Maestro to add infor-
mation to an entry and typically has an entry ID appended to the addtoentry_ value. That is
how Maestro knows into which entry the data should be placed. You can, of course, launch
jobs with such a disposition and let Maestro handle the incorporation, but if you plan on having
your customized job incorporation function handle incorporation, then you should avoid this
and the other values listed above.
The Python script needs to specify the disposition by launching its job with -DISP special-
value. Here special-value is the unique value mentioned above, like MyProcedure1. For a
given type of task that you perform you should use the same special-value for all instances.
Any value can be used (apart from those listed). You can even include additional information
in the special-value string to help you process the job results. You may nd it useful to base
part of the jobs disposition value on the name of your company, group, Python panel, script or
task.
7.3.2 Incorporating Results Using Your Specialized Incorporation
Function
The function maestro.job_incorporation_function_add(callback-function) takes a
single argument, the function to be called by Maestro whenever a job is available to be incor-
porated. The callback function should expect to receive two parameters. The rst is the job ID
(a string). The second is a Boolean that indicates if we are just testing whether the job can be
incorporated by the script or whether we really expect the script to try and do incorporation. If
this second parameter is False, then its OK for the script to actually attempt the incorpora-
tion.
The callback is called by Maestro for every job that is incorporatable. The callback must there-
fore check to see if it should handle each job that is ready for incorporation. This is why a
special disposition value helps the callback determine whether to handle the job results or not.
Chapter 7: Running Jobs from Scripts
Schrdinger Suite 2009 44
You can get the job disposition in the callback by creating a jobcontrol.Job instance based
on the job ID that is passed into the callback. Suppose we call our jobcontrol.Job instance
myjob, then to get the job disposition we use myjob. Disposition, and check to see if this
value matches the special-value job disposition that was used to launch your specialized job.
For example:
from schrodinger.job import jobcontrol
def my_job_incorporation_callback(jobid, testing):
myjob = jobcontrol.Job(jobid)
disposition = myjob.Disposition
split_disposition = disposition.split(':')
print split_disposition[0]
if split_disposition[0] == 'My disposition value':
print "This is my job and I will handle it."
# Add your code including returning the appropriate return value
If the callback function incorporates the job (processes the job results) or it is prepared to do
so, but the second parameter was True, then it should return maestro.WILL_HANDLE_JOB. If
the callback function is not able to handle the job at this time then it should return
maestro.NOT_INCORPORATABLE. If it is not going to handle the incorporation at all it should
return maestro.NOT_MY_JOB.
Returning maestro.WILL_HANDLE_JOB causes Maestro to treat the job as having been incor-
porated and so it will not itself try to incorporate the results.
7.3.3 Removing Your Job Incorporation Callback
You can remove a job incorporation callback by using the following function:
maestro.job_incorporation_function_remove(callback-function).
7.4 Running and Managing Jobs Outside Maestro
The Python modules include some powerful tools for running and managing jobs outside
Maestro. The schrodinger.job.jobcontrol module provides access to some of
Schrdingers job control functionality. It allows read access to the job database and the job
host list, and can help with launching subjobs.
7.4.1 Access to the Job Database
Read-only access to the job database is provided by the schrodinger.job.jobcontrol
class. A Job object can be created with a job ID string. These strings look like isabel-0-
434ac660 and are printed to the output of all Schrdinger jobs.
Chapter 7: Running Jobs from Scripts
Scripting with Python 45
Once a Job object is created, the available keys can be listed with the keys() method and
their values can be obtained as attributes of the object. The database values retrieved at creation
time will never be updated automatically. They must be explicitly updated with the
readAgain method.
This example from the interactive prompt demonstrates how to read the database, access
attributes, and update your information:
>>> import schrodinger.job.jobcontrol as jobcontrol
>>> j = jobcontrol.Job("isabel-0-434ac660")
>>> j.keys()
[BackendFifo, BackendPid, ChildPid, Command, Dir, Envs,
Home, Host, HostEntry, HostsFile, InputFiles, JobDB,
JobDir, JobFifo, JobHost, JobId, JobPid, JobPort,
JobUser, LaunchTime, LogFiles, MonitorInterval, Name,
OutputFiles, Processors, Program, StartTime, Status,
StatusTime, SubJobs, User]
>>> j.LaunchTime
2005-10-10-15:52:00
>>> j.LogFiles
[counterpoise.1146.blog]
>>> j.StatusTime
2005-10-10-17:18:31
>>> import time; time.sleep(1200) # wait a while
>>> j.StatusTime
2005-10-10-17:18:31
>>> j.readAgain()
7.4.2 Information on Job Hosts
A single function is provided to return a list of Host objects representing the information from
the appropriate schrodinger.hosts le. The Host class provides attributes for processors,
temporary storage (tmpdir), SCHRODINGER locations, and some less commonly needed
pieces of information. (See the module documentation for more information.)
This example function lists all hosts with multiple processors:
def list_multiprocessor_hosts():
import schrodinger.job.jobcontrol as jobcontrol
for host in jobcontrol.get_hosts():
if host.processors > 1:
print "%20s: %d" % (host.name, host.processors)
Chapter 7: Running Jobs from Scripts
Schrdinger Suite 2009 46
7.4.3 Running Jobs From Python
The jobcontrol.launch_job function provides a way to run a Schrdinger job from a
Python script. The single argument to this function is a Schrdinger command that you would
issue from the command line (with the exception that $SCHRODINGER need not be included).
This launch_job function returns a Job object.
This interactive example shows how to start a Jaguar job, do some other calculations, then wait
for the Jaguar job to nish.
>>> import schrodinger.job.jobcontrol as jobcontrol
>>> job = jobcontrol.launch_job("jaguar run water.in")
>>> job.Status
running
>>> import time; time.sleep(10) # pretend this is useful
>>> job.wait()
>>> job.Status
completed
>>> job.OutputFiles
[water.01.in, water.out]
Chapter 8
Scripting with Python 47
Schrdinger Suite Scripting with Python
Chapter 8: Writing Your Own Panels
All the scripts we have used so far have been run from the Maestro command line using the
pythonrun command. It is, however, possible to write scripts that display their own graphical
panels, similar to those of Maestro itself. You can use either the Tkinter toolkit or the PyQT
toolkit. To use the PyQT toolkit, you have to have a license for both QT and PyQT.
8.1 Using Tkinter
The Tkinter graphical user interface (GUI) toolkit for Python is simple to use and comes as a
standard part of Python. This section describes how to use Tkinter with Maestro. Learning to
program a GUI takes a bit of practice, but Tkinter and PMW make it relatively easy. For infor-
mation on using Tkinter, see the recommended OReilly books on Python or the following
page on the Pythonware website which offers a step-by-step tutorial. For information on PMW,
see http://pmw.sourceforge.net. You can also nd more examples using Maestro and Tkinter at:
$SCHRODINGER/python-vversion/scripts/maestro/
When a Tkinter program is running within Maestro both programs need to share event infor-
mation. Events in this context include mouse movements, mouse clicks, and key presses. Both
Maestro and the Python/Tkinter script respond to events. In order for a Tkinter script running
inside of Maestro to be able to share events with Maestro, special techniques are required.
First and foremost, never call mainloop() on any widget in your Tkinter script. If you do,
your script will run, but Maestro will be inactive while your Tkinter widget is visible. This
probably is not what you want since the real power of creating your own GUI panels is to allow
them to interact with Maestro.
Instead of using mainloop() use maestro.tk_toplevel_add() to notify Maestro when
you've built your panel and are ready to have it displayed. Maestro will then share the events it
receives with your panel and the two can interact. When you are nished with your panel and
want to dismiss it, call maestro.tk_toplevel_remove() to notify Maestro that you no
longer need to share events.
Note: Any number of Python/Tkinter scripts can be sharing events with Maestro.
Chapter 8: Writing Your Own Panels
Schrdinger Suite 2009 48
Example 1. simple.py
Here is an example that displays a simple panel in Maestro:
# simple.py
from schrodinger.maestro import maestro
from Tkinter import *
simple_top = 0
def simple_quit_com( *ignore ):
global simple_top
maestro.tk_toplevel_remove( simple_top )
simple_top.destroy()
simple_top = 0
def simple():
global simple_top
# Don't put the panel up twice:
if( simple_top != 0 ):
return
simple_top = Tk()
quit_button = Button( simple_top, text='Quit', command = simple_quit_com)
quit_button.pack()
maestro.tk_toplevel_add(simple_top)
We use maestro.tk_toplevel_add to let Maestro know when we are ready to display the
panel and maestro.tk_toplevel_remove when we are nished with it. Also notice the use
of simple_top as a check to see if the panel is currently displayed. Before putting up a panel,
it is generally good practice to see if the panel already exists. It can be confusing to have
multiple instances of the same panel oating around.
8.2 Supporting Atom Selection from the Workspace
One of the most interesting things you can do with your panels is to receive information about
which atoms are selected in the Workspace while your panel is active.
Note: If you request to receive selection information from Maestro, then no other panel
within Maestro (or any other Python/Tkinter script) can receive selection information.
By the same measure, if another panel starts receiving selection information (say it is
opened from the main Maestro menu) then your panel loses the ability to receive selec-
Chapter 8: Writing Your Own Panels
Scripting with Python 49
tion information. This is a natural consequence of the way atom selection operates in
the Maestro Workspace; picking information can only go to one place.
Example 2. simple_pick.py
Getting selections from the Maestro Workspace is simple. All you need to do is tell Maestro
the name of the Python function you want called when a selection is received. Here we have
extended the previous example by adding an additional function to receive atom selections.
Remember to tell Maestro you no longer want to receive events when the panel is closed.
# simple_pick.py
from schrodinger.maestro import maestro
from Tkinter import *
from schrodinger import structure
simple_top = 0
def simple_quit_com( *ignore ):
global simple_top
maestro.tk_toplevel_remove( simple_top )
maestro.picking_stop()
simple_top.destroy()
simple_top = 0
def simple_pick_cb( at ):
st = maestro.workspace_get()
pdb_res = st.atom[at].pdbres
print "Picked residue is: %s " % pdb_res
def simple_pick():
global simple_top
# Don't put the panel up twice:
if( simple_top != 0 ):
return
simple_top = Tk()
quit_button = Button( simple_top, text='Quit', command = simple_quit_com)
quit_button.pack()
maestro.picking_atom_start( "Pick atom to have residue type printed",
"simple_pick.simple_pick_cb" )
maestro.tk_toplevel_add(simple_top)
It is important to note that the function passed to maestro.picking_atom_start() must
be fully qualied with the name of the function and the module, in this example,
simple_pick.simple_pick_cb().
Chapter 8: Writing Your Own Panels
Schrdinger Suite 2009 50
The function that receives selections should be prepared to receive a single parameter, the atom
number of the selected atom in the Workspace. Once you have the atom number you can use
that to operate directly on the Workspace structure as shown in this example, or use it to issue
Maestro commands.
8.3 Creating Panels with a Maestro Look and Feel
The Python tools contain some additional modulesthe schrodinger.ui packagethat
make it easier to create panels that better integrate with Maestro. In their simplest form, these
modules provide interfaces to the standard Tkinter and PMW widgets, precongured to ensure
that the appearance of the resulting panels closely matches that of Maestro itself. We strongly
encourage you to use this package to build panels that interface to Maestro, because it avoids
some of the problematic interactions between certain PMW widgets and Maestro.
Example 3. simple.py
Heres another version of Example 1, which uses the Schrdinger interface to Tkinter:
# simple.py
from schrodinger.maestro import maestro
import schrodinger.ui.widget as stk
simple_top = 0
def simple_quit_com( *ignore ):
global simple_top
maestro.tk_toplevel_remove( simple_top )
simple_top.destroy()
simple_top = 0
def simple():
global simple_top
# Dont put the panel up twice:
if( simple_top != 0 ):
return
simple_top = stk.Tk()
quit_button = stk.Button( simple_top, text=Quit,
command = simple_quit_com)
quit_button.pack()
maestro.tk_toplevel_add(simple_top)
Chapter 8: Writing Your Own Panels
Scripting with Python 51
There are a number of other facilities that are provided by these modules - we suggest you look
at the reference documentation for more details.
8.4 Adding a Help Topic to a Panel
You can make use of the existing Maestro help system to add a help topic to your panel, and
link it to a Help button. This allows you to easily link your help topics to existing Maestro help
topics, for example. The steps in adding the help topic are as follows:
1. Create an HTML topic le and store it with the other Maestro help topics.
The help topics and supporting les are stored in $SCHRODINGER/docs/maestro/
help/mae90_help, for all products. The topics themselves are in subdirectories, but
you can store your own topic wherever you like in this directory. However, we suggest
that you create a subdirectory for your own topics, or put it in the relevant existing
subdirectory.
If you want the topic to be available to all users, you should store it in this directory, but
you must have write permissions to do so. If you dont have write permissions, or you just
want to make your own version of the help, copy the contents of this directory to a new
location (call it myhelpdir), and add your topics to the new location.
2. Choose a topic ID, and add the ID and the relative URL to the map le,
help_map_file.
This le is in $SCHRODINGER/docs/maestro/help/mae90_help. Topic IDs must be
unique. They are usually upper case, constructed from the path to the help topic. The
URL is given relative to the location of help_map_file, which by default is
$SCHRODINGER/docs/maestro/help/mae90_help.
3. Add the following line to import the help module:
import pyhelp
The pyhelp module is included in the site packages of the Python version installed with
the Schrdinger software.
4. Add the following call to identify the help set to which you have added the topic:
pyhelp.set_help_product("Maestro")
With this call, the Maestro help set in the standard location is used. The call also sets the
title of the help set and various identiers used by the help server. If you have copied the
help directory to another location, you must also set the environment variable
SCHRODINGER_HELP_DIR to myhelpdir.
Chapter 8: Writing Your Own Panels
Schrdinger Suite 2009 52
5. Add the following command to the code for the action of your Help button:
pyhelp.show_help_topic("MY_TOPIC_ID")
and replace MY_TOPIC_ID with the topic ID that you added to the map le.
These commands allow you to open the help when you open the panel as a standalone panel as
well as opening it from Maestro.
If you have made a local copy of the help, you will have to set the environment variable
SCHRODINGER_MAESTRO_HELP to myhelpdir before you start Maestro in order to use this
copy. If you are running the panel as a standalone application, you will have to set the environ-
ment variable SCHRODINGER_HELP_DIR to myhelpdir.
If integrating the help topic into the Maestro help is inconvenient, you can use the pyhelp
module to open an independent HTML le as a help topic. This allows you to install the script
anywhere, but it does not in general allow you to link to the Maestro help. To open an HTML
le for a script, there are two methods available:
Store the HTML le for scriptname.py in the directory scriptname_dir (relative to the
script), and name it scriptname.html. You can then open the help topic with the follow-
ing command:
pyhelp.show_help_topic(__file__)
Store the HTML le anywhere, and pass the absolute path to the le to open the topic:
pyhelp.show_help_topic(abs-path-to-topic)
For both of these methods, you must import the pyhelp module. If you do not call
pyhelp.set_help_product, the default is set to Schrodinger. The rst of these methods
is useful if you want to write a script and then install it on the Maestro Scripts menu. The
second is the most general method, and can be used for any HTML le.
For more information on customizing the help, see Appendix E of the Maestro User Manual.
Chapter 9
Scripting with Python 53
Schrdinger Suite Scripting with Python
Chapter 9: Registering Python Functions with
Maestro
Normally, the Python functions you write for use in Maestro will be called explicitly with the
pythonrun command. However, there are some situations in which you may want to supply a
Python function that will be called when particular events occur during the normal operation of
Maestro. These functions, sometimes known as callbacks, are an important method for
extending and modifying the default behavior of Maestro. You have already seen one example
of a callback function at work in the previous chapter, where we used
maestro.picking_atom_start() to register a Python function that was called by Maestro
when an atom was selected in the Workspace. There are two additional callback functions that
can be used to extend the capabilities of Maestro.
9.1 Periodic Functions
If you need to perform an action periodically, you can use:
maestro.periodic_callback_add(your_callback_function_name)
to register a Python function that will be called approximately 20 times a second. If you would
like to perform the action at a lower frequency, maintain a counter in your function and only
perform the action once every N times your callback function is called (i.e. every 20 to get
about once a second).
Example 1. spin.py
Here is a simple example to show how this works:
#spin.py
# Register a periodic callback to spin the molecule
from schrodinger.maestro import maestro
def start_spin():
maestro.periodic_callback_add( "spin.spin_cb");
# Unregister the callback:
def stop_spin():
maestro.periodic_callback_remove( "spin.spin_cb" );
# The periodic callback:
def spin_cb():
maestro.command("rotate y=5");
Chapter 9: Registering Python Functions with Maestro
Schrdinger Suite 2009 54
When you issue the pythonrun spin.start_spin command, the contents of the Work-
space will be rotated around the Y-axis. This will continue until you explicitly issue the
pythonrun spin.stop_spin command.
When you register a callback you should use the fully qualied module.function form. You
can register as many periodic callback functions as you like during a Maestro session. When
nished performing the periodic action, remember to unregister your callback function using:
maestro.periodic_callback_remove(your_callback_function_name)
Note: A registered callback function should not attempt to remove itself.
9.2 Mouse Hover Functions
You can also register a callback function, using:
maestro.hover_callback_add(your_callback_function_name)
that will be called by Maestro whenever the pointer is paused (hovers) over an atom in the
Workspace. In this example we demonstrate the mouse hover callback by utilizing the Maestro
feature that allows atom-specic information to be displayed in the Workspace status bar.
Example 2. hover.py
The following example replaces the default string in the status bar with the atom number and
partial charge of the atom the pointer is paused over:
#hover.py
from schrodinger.maestro import maestro
from schrodinger import structure
_last_atom = -1;
def set_hover():
maestro.hover_callback_add( "hover.hover_cb" )
def clear_hover():
maestro.hover_callback_remove( "hover.hover_cb" )
def hover_cb( at ):
global _last_atom
if( at == _last_atom ):
return
if at > 0 :
st = maestro.workspace_get()
pcharge = st.atom[at].partial_charge
maestro.feedback_string_set("Atom: %d Charge = %5.3f" % (at, pcharge))
Chapter 9: Registering Python Functions with Maestro
Scripting with Python 55
_last_atom = at
return;
Note: Register the callback function using the full module.function form. When you no
longer need the mouse hover callback, unregister your function using:
maestro.hover_callback_remove(your_callback_function_name)
9.3 Workspace Drawing and Changed Callbacks
You can add a Python function that will be called each time the Workspace is drawn using
maestro.workspace_draw_function_add(). This means that basically anything that can
be rendered with OpenGL can be drawn in the Workspace. Often used in conjunction with this
it is also possible to register a callback that will be called when the contents of the Workspace
are modied: maestro.workspace_changed_function_add().
The callback function in this case is called with a string parameter that indicates exactly what
has been modied in the Workspace. It will be one of:
everything
color
geometry
visibility
representation
properties
coordinates
connectivity
unknown
In this way a script that does not care about, say, changes in the representation of the structure
in the Workspace can choose to take no action in these cases.
Here is a very simple example to illustrate how these functions can be used together in order to
display a sphere at the centroid of each molecule present in the Workspace. In this instance the
centroid calculation is only performed when we are notied that the Workspace has changed
and not each time we draw. This allows the draw performance to be kept as fast as possible:
from schrodinger.maestro import maestro
from schrodinger.graphics3d import sphere
sphere_group=0
def run():
Chapter 9: Registering Python Functions with Maestro
Schrdinger Suite 2009 56
# Register the callbacks and setup the drawing with the initial
# contents of the workspace
update("everything")
maestro.workspace_changed_function_add("spherecent.update")
maestro.workspace_draw_function_add("spherecent.draw_cb")
maestro.redraw()
def stop():
# Turn off the drawing:
maestro.workspace_changed_function_remove("spherecent.update")
maestro.workspace_draw_function_remove("spherecent.draw_cb")
maestro.redraw()
def draw_cb():
global sphere_group
if sphere_group != 0:
sphere_group.draw()
def update( changed ):
# Calculate a transparent sphere for the centroid of each molecule:
global sphere_group
# We only care about changes to the actual structure and its
# geometry. Things like color, representation dont matter:
if changed in ["everything","geometry","connectivity","unknown"]:
sphere_group = sphere.SphereGroup()
st = maestro.workspace_get()
for mol in st.molecule:
xcent = 0.0
ycent = 0.0
zcent = 0.0
for iatom in mol.atom:
xcent += iatom.x
ycent += iatom.y
zcent += iatom.z
xcent = xcent / len(mol.atom)
ycent = ycent / len(mol.atom)
zcent = zcent / len(mol.atom)
sp = sphere.Sphere(x=xcent, y=ycent, z=zcent,
radius=.5, resolution=15,
transparency=0.5, r=1.0, g=0.0, b=1.0)
sphere_group.add(sp)
Chapter 10
Scripting with Python 57
Schrdinger Suite Scripting with Python
Chapter 10: Debugging Your Scripts
Even if you are an experienced script writer, you are going to occasionally make mistakes.
Now the task of debugging commences. This chapter discusses strategies for determining what
has gone wrong with your script.
10.1 The Power of print
One of the simplest and at the same time most valuable Python debugging tools is the print
statement. Since all the Python built-in types, including lists and dictionaries, can be printed,
judicious placement of temporary print statements can often provide enough information to
nd even difcult errors. Note that the output resulting from a print statement appears in the
window from which you started Maestro.
10.2 The pdb Module
Powerful as it is, sometimes the print statement is not going to give you enough information
to nd the problem. Fortunately, Python comes with a debugger (pdb) you can use even when
your script is running in Maestro. You can nd a complete description of pdb at
www.python.org.
Example 1. spin_debug.py
It is easy to use pdb with your scripts. Simply create a special version of your main function
that passes control to pdb, then call the modied function from Maestro. To illustrate, we are
going to extend one of our previous examples:
#spin_debug.py
import pdb
from schrodinger.maestro import maestro
import time
def spin(axis="y",step=10,slp=0.1):
total_rotate=0
if axis != "y" and axis != "x" and axis != "z" :
raise Exception, "Can't use axis: " + axis
Chapter 10: Debugging Your Scripts
Schrdinger Suite 2009 58
while total_rotate < 360.0 :
maestro.command("rotate %s=%d" % (axis,step))
maestro.redraw()
total_rotate += step
time.sleep(slp)
return
def spin_debug( *args ):
pdb.run("spin.spin()")
Now, calling spin_debug from Maestro using pythonrun will run the script in the Python
debugger, giving you access to all its debugging tools. From the (Pdb) prompt at the main
window enter "b spin.spin" to set a breakpoint at the spin.spin() method. Next enter
"c" to continue execution up to the breakpoint.
(Pdb) import spin
(Pdb) b spin.spin
Breakpoint 1 at /home/user/.schrodinger/maestroversion/scripts/
spin.py:23
(Pdb) c
> /home/user/.schrodinger/maestroversion/scripts/spin.py(23)spin()
-> total_rotate=0
Once you are at the breakpoint, use "n" to step line by line through the function and "p" to print
current values of the variables. For a full list of available commands see the Python pdb
website.
Chapter 11
Scripting with Python 59
Schrdinger Suite Scripting with Python
Chapter 11: The Maestro Scripts Menu
To this point, all our Python scripts have been run from the Maestro command line using
pythonrun. While this works well during development and for occasional use, it can be quite
cumbersome for frequently used, mature scripts. The Maestro Scripts menu offers a readily
accessible home for all your frequently used scripts.
You can add scripts to this menu directly in Maestro (see Chapter 13 of the Maestro User
Manual for details). Or you can add scripts to the Scripts menu manually by editing the
scripts.mnu le as described below.
11.1 The scripts.mnu File
The key to adding your scripts to the Maestro Scripts menu is to add a new entry for each script
to the scripts.mnu le. This le is located in the .schrodinger/maestroversion direc-
tory in your home directory. You can create this le if it does not already exist.
The format for the scripts.mnu le is simple. There is one entry for each menu item. Each
entry consists of two lines. The rst describes the menu item itself. The second denes the
command that will be run when that menu item is selected. In the next example we make our
spin script available from the Scripts menu by creating a $HOME/.schrodinger/
maestroversion/scripts.mnu le containing the entry:
Spin
pythonrun spin.spin Y 30 0.1
The next time you start Maestro the Spin item will be available on the Scripts menu. Note how
we have supplied arguments to the spin.spin command. This mechanism is not limited to
running Python scripts. You can issue any Maestro command from the Scripts menu.
Depending on your personal preferences, this can be an effective alternative to pythonrun.
11.2 Cascading Menus
Since there is a practical limit to the number of items you can place on a single menu, you
probably will not want to add all your favorite scripts directly to the Scripts menu. By using
cascading submenus you can not only organize related scripts, but in the process keep the top
level Scripts menu more manageable. In this example we build a cascading submenu. We also
illustrate how several entries in a single submenu can initiate the same command, each
Chapter 11: The Maestro Scripts Menu
Schrdinger Suite 2009 60
supplying different arguments. To dene a cascading submenu, place a colon (:) in the rst
line of the entry:
Spin:X
pythonrun spin.spin X 10
Spin:Y
pythonrun spin.spin Y 10
Spin:Z
pythonrun spin.spin Z 10
Now we have a single Spin item in the top level Scripts menu. Spin contains a cascading
submenu with items X, Y, and Z. Each item causes the contents of the Workspace to rotate
about a different axis.
Note: You can only specify one level of cascading submenu items. You can not create an
entry like the following:
Category:subcategory:item
11.3 Creating Scripts to be Installed in Maestro
As mentioned earlier it is possible to use Maestro to install scripts into the Scripts menu. To do
this use the Manage... item in the Scripts menu. This works best when the script has been
congured with some additional information which can be displayed in the installation dialog
in Maestro. There are three things which are required to be added to the script to fully support
being able to install it via Maestro:
1. A module-level doc string that is assigned to __doc__. This looks like:
__doc__= """
A description of the script
Author
Date
"""
This doc string is displayed as the description of the script when the user selects the script
in the Maestro script installation dialog box. It should be informative enough so that the
user knows exactly what the script does.
2. A comment that begins with #Name: For example:
#Name: Display all distances from an atom
This is the text that will be displayed in the Scripts menu when the script is installed. The
user has the option to edit this text at the point of installation but a useful default should
be supplied.
Chapter 11: The Maestro Scripts Menu
Scripting with Python 61
3. A comment that begins with #Command:. For example:
#Command: pythonrun alldist.alldist
This is the command that will be used to run the script once is it installed in the Scripts menu.
Schrdinger Suite 2009 62
Chapter 12
Scripting with Python 63
Schrdinger Suite Scripting with Python
Chapter 12: Tips and Traps
12.1 Things to Watch Out For
This section is a collection of tips and techniques we have found useful. If you are having
trouble making your script do what you want, you may nd a solution here.
The maestro module can only be used for scripts that are running inside Maestro. While
the other modules like structureutil and mm can be used for scripts run with Python
outside Maestro, the maestro module requires code that exists inside Maestro. (The next
section describes a method for creating modules that can be used in a variety of situa-
tions.)
Atoms and bonds are indexed from 1 (not 0) in functions that manipulate the structure.
12.2 Things That Might be Useful
Here are some things we have found useful:
Emacs and Idle both provide many useful functions for creating and validating Python
scripts. In Emacs, typing CTRL-C CTRL-C checks the syntax of the current le. Idle is
provided with the distribution in $SCHRODINGER/utilities.
A script that is executing within Maestro can be interrupted by typing CTRL+C in the ter-
minal window in which Maestro was started.
Modules are a great way to organize your code. When you create a set of functions you
think are useful in multiple scripts, create a module to hold the scripts and place it in the
module search path (for example .schrodinger/maestroversion/scripts in your
home directory). This makes the functions available for use in all your scripts.
Even though the maestro module cannot be used outside Maestro, it is possible to write
a module that includes maestro, and can be included as a module in another script or run
as a stand-alone script. Here is an example:
# pdbname.py
def assign_pdb_names( ct, res_names = True, atom_names = True ):
# Body not shown:
if __name__ == '__main__':
Chapter 12: Tips and Traps
Schrdinger Suite 2009 64
#Running as stand-alone script:
structureutil.for_all_structures( sys.argv[1], assign_pdb_names,
sys.argv[2], "Maestro", "Maestro", True, True)
else:
# Are we running inside Maestro?
try:
from schrodinger.maestro import maestro
def pdbname():
st = maestro.workspace_get()
assign_pdb_names(st)
maestro.workspace_set(st)
except
pass
This script can be used as follows:
From within Maestro: pythonrun pdbname.pdbname
As a stand-alone script:
$SCHRODINGER/run pdbname.py inle outle
Imported into another module: import pdbname
Chapter 13
Scripting with Python 65
Schrdinger Suite Scripting with Python
Chapter 13: Running Scripts Outside Maestro
13.1 Running Your Scripts
Although it is not possible to use any of the methods from the maestro module when running
outside Maestro, it is possible to use the structure and structureutil modules. It is best
to use the version of Python we supply, as this ensures that all the necessary environment vari-
ables are set up before your script is run. You can run Python scripts using this version with the
command $SCHRODINGER/run.
$SCHRODINGER/run is most commonly used to run a script that is located in the local direc-
tory and expects as arguments the name of that script and any arguments for the script.
However $SCHRODINGER/run can also be used to run scripts that are installed in standard
locations. If the named script is not in the local directory then the following places are searched
in order until a script of the given name is located:
The location specied by the environment variable SCHRODINGER_SCRIPTS (if set).
The directory $HOME/.schrodinger/scriptsX.Y where X and Y are the current
mmshare major and minor version numbers (1.7 for the 2009 release).
The directory $SCHRODINGER/mmshare-X.Y/python/common.
The directory $SCHRODINGER/mmshare-X.Y/python/scripts.
The Schrodinger script installation tools support installation into the rst three of these loca-
tions, provided you have write permission to the directories.
The Schrdinger Python installation uses the PYTHONPATH environment variable in the same
way as any other Python installation. So if you want to use your own modules with the
Schrdinger modules, you can include the path to your modules in PYTHONPATH. However,
these modules must be compatible with Python 2.5 (and for Linux-x86 they must be 32-bit).
If you want to maintain a set of modules for an incompatible Python installation in
PYTHONPATH, you can set the environment variable SCHRODINGER_PYTHONPATH so that you
can use the Schrdinger modules. This environment variable is used instead of PYTHONPATH
when running Python with the Schrdinger installation, if it is dened. To simply override
PYTHONPATH, set SCHRODINGER_PYTHONPATH to an empty string. To add compatible
modules, set it to the path for the compatible modules. Because Maestro and several of the
scripts that run jobs use Python, it is important to set SCHRODINGER_PYTHONPATH if
PYTHONPATH contains the path to incompatible standard modules.
Chapter 13: Running Scripts Outside Maestro
Schrdinger Suite 2009 66
The main difference between running a script inside and outside Maestro is how you gain
access to structures. When running a script inside Maestro, you can get structures from the
Workspace or the project. However, in your stand-alone scripts you need to read the structures
directly from the les. Fortunately this is easy. Short lter scripts can be created that read struc-
tures from one le and write modied versions or subsets of those structures to another le.
13.2 Simple Filters
Reading structures is best done with the StructureReader class. The structure reader knows
how to read from PDB, SD (MDL), or Maestro les. If the format is not specied explicitly,
the le sufx is used to determine the format:
Once you have a structure object, it knows how to write or append itself to a specied le.
Again, the format can be PDB, SD, MOL2, or Maestro. If the format is not specied explicitly,
the le sufx is used.
Example 1. Read a le and write a new le
Here is an example of a lter that reads a le and writes to a new le all the structures that
contain a chlorine atom:
#findcl.py
from schrodinger import structure
import sys
import os
in_file, out_file = sys.argv[1], sys.argv[2]
if os.path.exists(out_file):
os.remove(out_file)
.ent
.pdb
PDB
.sd
.sdf
.mol
SD
.mol2 Tripos mol2
.mae.gz
.maegz
Gzip compressed Maestro
.mae Maestro
Chapter 13: Running Scripts Outside Maestro
Scripting with Python 67
for s in structure.StructureReader(in_file, format='maestro'):
for iatom in s.atom:
if iatom.atomic_number == 17:
s.append(out_file, format="maestro")
break
To run this script, enter the following command:
$SCHRODINGER/run findcl.py inle.mae outle.mae
Note: In this case, the format is specied explicitly as format=maestro so this only oper-
ates on Maestro les, regardless of the le sufx. Any number of operations could be
performed on the structure before it is written out again.
There is also a mechanism for examining the properties of the structures in the le. For
example, you could examine those quantities that are calculated and added to a le by
programs like Glide, QikProp, or MacroModel. The "property" eld of the structure class can
be used as a Python dictionary to get and set properties associated with that structure.
Note: When operating from les, you must use the property name exactly as it appears in the
le. Also if you create a property name, it must conform to the following prex
convention, based on the type of data you wish to add:
The following example creates a new integer property. When the output le is imported into
Maestro, this new property appears in the Project Table as My Sum.
s.property['i_user_My_Sum']= sum
Example 2. Properties from a Glide pose viewer le.
The following example shows how to use the properties from a Glide pose viewer le.
Note: No explicit format is given, so the sufx of the input and output le determine the
format. The receptor (rst structure) is omitted and the remaining ligand poses are only
written to the input le if the GlideScore is less than -4.5.
#glidekeep.py
from schrodinger import structure
import sys
import os
Real number r_user_
Integer i_user_
String s_user_
Boolean b_user_
Chapter 13: Running Scripts Outside Maestro
Schrdinger Suite 2009 68
in_file, out_file = sys.argv[1], sys.argv[2]
if os.path.exists(out_file):
os.remove(out_file)
for (ix, st) in enumerate(structure.StructureReader(in_file)):
if ix > 0:
if st.property['r_i_glide_gscore'] < -4.5:
st.append(out_file)
Appendix A
Scripting with Python 69
Schrdinger Suite Scripting with Python
Appendix A: Reference Modules
The Schrdinger installation of Python includes a schrodinger package, that contains a
number of other packages and modules. The descriptions of these packages and modules are in
HTML format and are located in the following directory:
$SCHRODINGER/docs/general/python/suite08_python_scripting
Links to these documents are provided in the HTML version of this manual, and also from the
Maestro Help menu (choose Python API). The version that is displayed from Maestro has a
full-text search capability. You can also open the le schrodinger_nosearch.html in this
directory and navigate to the documentation from there. The main packages are described in
Table A.1.
Table A.1. Description of supplied modules.
Module Description
application Application-specic functions
graphics3d Support for drawing in the Workspace
infra Low-level package with tools not intended for general script usage. We
reserve the right to change these modules as we feel necessary.
job Functions for launching and managing jobs
maestro Functions used for interaction with Maestro
project Functions used with Maestro projects, either inside or outside Maestro
protein Package for capping, analyzing, and adding hydrogens to proteins.
structure Functions to read, write, and manipulate structures
structureutil Functions that operate on structure objects: nding rings and matching
SMARTS expressions, etc.
structutils Package for modules of structure utilities
ui Graphical user interface tools. Fixes some bugs in Tkinter and PMW that
cause bad interactions with Maestro. Use these to ensure consistent look and
feel with Maestro. Lastly, provides reusable specialized components.
utils Utility functions - logging script operations and standardized processing of
command line options.
Schrdinger Suite 2009 70
Appendix B
Scripting with Python 71
Schrdinger Suite Scripting with Python
Appendix B: The MacroModel Python Package
MacroModel is a force-eld based, molecular mechanics program. The input for a Macro-
Model calculation is a command (.com) le. The .com le contains the name of the input
structure le on which to operate, the name of the output structure le, and a list of operation
codes (opcodes) that describe how to perform the calculation. The ComUtil class, in the
utils.py module, facilitates creating properly formatted command les. XCluster is a tool
used to analyze collections of conformers. CluUtil, also in utils.py, is a class for writing
input command (.clu) les used by XCluster.
The classes in the utils.py module provide a complement to the maestro.command()
facility. Because it does not rely on the Maestro command language, it extends your capability
to prepare and run MacroModel .com les, and XCluster .clu les, beyond what is currently
supported in the Maestro command language.
B.1 The ComUtil Class
The ComUtil class has dictionary attributes for a wide assortment of opcodes. The method
writeComFile() accepts an array of job input, job output, and a list of opcodes. For each
opcode in the list, the arguments for that opcode are looked up in the associated opcode dictio-
nary. The dictionary uses numerical keys that correspond to the index of the opcode argument.
Default dictionary values are given to make almost any job runnable.
The features of the ComUtil class are:
generation of arbitrary .com les with control over all opcode arguments
inclusion of DEBG switches to control execution details and verbosity
preparation of distributed jobs via NPRC
library of methods to write common job types, such as:
energy listing
energy and derivative listing
energy minimization
energy minimization with redundant conformation elimination
geometry reporting
conformational searches using all the available methods
COPY and ALGN
free energy perturbations
logP
Appendix B: The MacroModel Python Package
Schrdinger Suite 2009 72
eMBrAcE optimizations
Atom set interactions
Monte Carlo/Stochastic Dynamics
Stochastic Dynamics
Mode Integration (MINTA)
The remainder of this section provides tutorial examples in the use of the ComUtil class. The
tutorial assumes an understanding of MacroModel opcodes, and the .com le format. For more
information, see the MacroModel Reference Manual. The examples below include code that
can be saved to a le and executed with $SCHRODINGER/run script-le-name.
Example 1. Writing a simple energy listing .com le
The utils.py module contains a class for writing MacroModel .com les.
# mmod_tut1.py
import schrodinger.application.macromodel.utils as mmodutil
mcu = mmodutil.ComUtil() # create a default instance of the class
com_file_args = [
'mmod_tut1.com', # The name of the com file to write.
'input.mae', # The name of the input structure file.
'output.mae', # The name of the output structure file.
'EXNB',
'BDCO',
'FFLD',
'READ',
'ELST'
]
mcu.writeComFile(com_file_args)
The rst step is to import the MacroModel package into the scripts namespace. Then a new
instance of the ComUtil class is made, and a list of inputs and opcodes to describe the calcula-
tion is created. The last line writes the .com le. As each opcode is written to the le, the argu-
ments for each position are looked up in the dictionary for that opcode. The output from this
example is as follows:
input.mae
output.mae
EXNB 0 5 0 0 8.0000 20.0000 4.0000 8.0000
BDCO 0 0 0 0 0.0000 99999.0000 0.0000 0.0000
FFLD 14 0 0 0 1.0000 0.0000 0.0000 0.0000
READ 0 0 0 0 0.0000 0.0000 0.0000 0.0000
ELST -1 0 0 0 0.0000 0.0000 0.0000 0.0000
Another way to accomplish the same task is to call the related ComUtil method. ComUtil has
methods to write .com default les for most common MacroModel jobs. See the module docu-
mentation for a description of the methods.
Appendix B: The MacroModel Python Package
Scripting with Python 73
# mmod_tut1a.py
import schrodinger.application.macromodel.utils as mmodutil
mcu = mmodutil.ComUtil()
com_file_name = mcu.elst('mmod_tut1a.mae')
# mmod_tut1b.py
import schrodinger.application.macromodel.utils as mmodutil
mcu = mmodutil.ComUtil()
com_file_name = mcu.elst('molecule.mae', 'my_job.com')
This script also starts by importing the package, and create a default instance. Then the elst
method is called with the input le as the argument to the method. The predened methods
take the name of the input structure le as the rst required argument. The second, optional,
argument is the name of the .com le. These methods return the name of the le written, and
automatically create appropriate le names for the output structure and .com le.
The task methods have some logic to automatically determine a reasonable name for the .com
le and output structure le. Unless supplied, the name of the .com le is based on the input
structure le. For example, myfile.mae generates the command le name myfile.com. The
structure output le name is based on the name of .com le. In Example 2a, printing the value
of com_file_name would produce molecule.com, and inspection of the .com le would
show that the structure output le is named molecule-out.mae. In Example 2b, the .com
le is my_job.com, and the structure output le is my_job-out.mae.
Example 2. Customizing the opcode arguments for the ComUtil instance
The opcode dictionaries for the ComUtil instance may be altered prior to writing the .com
le, as illustrated in this example.
# mmod_tut2.py
import schrodinger.application.macromodel.utils as mmodutil
mcu = mmodutil.ComUtil()
mcu.MINI[1] = 9 # use TNCG - Truncated Newton Conjugate Gradient minimizer
mcu.CONV[5] = 0.0001 # Halt when gradient reaches this stringent value
mcu.mini('mmod_tut2.mae')
Each opcode dictionary uses numerical keys that correspond to an arguments position in the
.com le: thus a key of 1 corresponds to arg1 for an opcode. For example, MINI[1] selects the
minimizer method, and MINI[3] sets the number of minimization iterations. Here, the mini-
mization method and the convergence criteria are altered rst, then the .com le is written.
Appendix B: The MacroModel Python Package
Schrdinger Suite 2009 74
Example 3. Customizing the ComUtil instance attributes
Some opcodes may be enabled or disabled when constructing the instance, or afterward by
setting the appropriate boolean attribute.
# mmod_tut3a.py
import schrodinger.application.macromodel.utils as mmodutil
mcu1 = mmodutil.ComUtil(solv=True, nant=True)
mcu1.mcmm('mmod_tut3_1of2.mae')
mcu2 = mmodutil.ComUtil()
mcu2.solv = True
mcu2.nant = True
mcu2.mcmm('mmod_tut3_2of2.mae')
In this example script, the rst ComUtil instance is created with True solv and nant
attributes by passing settings to the constructor, while the second ComUtil instance sets the
attributes afterward. The attributes are read-write, so both paradigms are equivalent.
Some boolean attributes in the ComUtil class trigger a cascade of other changes to the instance
when True. For example, describing a calculation with a distance-dependent dielectric electro-
static potential may be achieved in one action by setting the ddde attribute to True.
# mmod_tut3b.py
import schrodinger.application.macromodel.utils as mmodutil
mcu1 = mmodutil.ComUtil(ddde=True)
mcu1.mcmm('molecule1.mae', 'mmod_tut3b.com')
When the ddde attribute is set to True, FFLD arg2 is set to 2, and FFLD arg5 is set to 4.0. In
addition, the incongruent solv attribute is set to False to disable the SOLV opcode. Another
boolean that causes a multiple changes in the opcode dictionaries is serial, which sets AUTO
arg6 to 1, and is used by some methods to adjust MCOP arg4 appropriately.
Example 4. Running jobs
The preferred mechanism to launch jobs from Python scripts is with the
schrodinger.job.jobcontrol interface. Two examples are given here.
# mmod_tut4a.py
import schrodinger.job.jobcontrol as jobcontrol
import schrodinger.application.macromodel.utils as mmodutil
mcu = mmodutil.ComUtil()
com_file_name = mcu.elst('mmod_tut4a.mae')
cmd_args = ['bmin', com_file_name[:-4], '-HOST', 'cluster']
job = jobcontrol.launch_job(cmd_args)
job.wait()
print "done"
Appendix B: The MacroModel Python Package
Scripting with Python 75
The launch_job() method takes a list of command-line words and runs the command. If the
job launch is successful, the job variable can be used to control and investigate the status of the
job. The function determines the correct installation and quotes words as needed. Here, the
command line equivalent is:
$SCHRODINGER/bmin mmod_tut4a -HOST cluster
In this example, job.wait() blocks execution of the script until the task is completed.
# mmod_tut4b.py
import schrodinger.job.jobcontrol as jobcontrol
import schrodinger.application.macromodel.utils as mmodutil
mcu = mmodutil.ComUtil()
cmd_args = mcu.getLaunchCommand(mcu.elst('mmod_tut4b.mae'))
job = jobcontrol.launch_job(cmd_args)
The getLaunchCommand() method returns a list of command line words. The list is provided
to launch_job(), which runs the command and returns a job instance. The list includes the
name of the executable (bmin), and the jobname (the root of the .com le), and other instance
attributes if set. Here, the command line equivalent is:
$SCHRODINGER/bmin mmod_tut4b
Instance attributes can be used to include command line options and their arguments, such as
LOCAL and -HOST, when getLaunchCommand() is called, as illustrated in the next
example.
# mmod_tut4c.py
import schrodinger.job.jobcontrol as jobcontrol
import schrodinger.application.macromodel.utils as mmodutil
mcu = mmodutil.ComUtil(host='cluster', local=True)
cmd_args = mcu.getLaunchCommand(mcu.elst('molecule1.mae'))
job = jobcontrol.launch_job(cmd_args)
Example 5. Running a para_bmin job
MacroModel support two distinct mechanisms for parallel job processing. This example
demonstrates the use of para_bmin, which runs a task in a distributed fashion. See the Macro-
Model Reference Manual for a description of tasks that are supported by para_bmin.
# mmod_tut5a.py
import schrodinger.application.macromodel.utils as mmodutil
import schrodinger.job.jobcontrol as jobcontrol
mcu = mmodutil.ComUtil()
com_file_name = mcu.mcmm('mmod_tut5a.mae')
cmd_args = [
'para_bmin',
com_file_name[:-4],
Appendix B: The MacroModel Python Package
Schrdinger Suite 2009 76
'-HOST',
'monica_s:50',
'-NJOBS',
'50'
]
job = jobcontrol.launch_job(cmd_args)
The command line equivalent is:
$SCHRODINGER/utilities/para_bmin mmod_tut5a -HOST monica_s:50 \
-NJOBS 50
Instance attributes can be used to dene the executable, bmin or para_bmin, returned by
getLaunchCommand.
# mmod_tut5b.py
import schrodinger.application.macromodel.utils as mmodutil
import schrodinger.job.jobcontrol as jobcontrol
mcu = mmodutil.ComUtil(para_bmin=True, para_bmin_njobs=50, host="monica_s:50")
cmd_args = mcu.getLaunchCommand(mcu.mcmm('mmod_tut5b.mae'))
job = jobcontrol.launch_job(cmd_args)
The command line equivalent is:
$SCHRODINGER/utilities/para_bmin mmod_tut5b -HOST monica_s:50 \
-NJOBS 50
Example 6. Running a job using internal distribution
Some MacroModel job types may be distributed to a dened list of hosts by MacroModels
internal distribution mechanism with the NPRC opcode. A ComUtil instance with nprc=True
sets the NPRC opcode. The hostfile attribute species the desired host le to use for the job.
See the MacroModel Reference Manual for more information on distributed MacroModel jobs.
# mmod_tut6.py
import schrodinger.application.macromodel.utils as mmodutil
import schrodinger.job.jobcontrol as jobcontrol
mcu = mmodutil.ComUtil(nprc=True)
com_file_name = mcu.mcmm('mmod_tut8.mae')
host_list = ['iman', 'heena', 'wena']
mcu.hostfile = mmodutil.write_hst_file(com_file_name, host_list)
job = jobcontrol.launch_job(mcu.getLaunchCommand(com_file_name))
The Monte Carlo Multiple Minima .com le has the NPRC opcode included. The command-
line equivalent is:
$SCHRODINGER/bmin mmod_tut6 -HOSTFILE mmod_tut6.hst
Appendix B: The MacroModel Python Package
Scripting with Python 77
The NPRC opcode instructs MacroModel to use its internal method of task distribution. The
hostle attribute is inserted into the command.
B.2 The CluUtil Class
The CluUtil class has dictionary attributes for most cluster instructions. The method
writeCluFile() accepts an input le (structures or distance matrix), and builds the
jobname.clu le using the class attributes. For each cluster instruction list, the dened values
in the class are looked up. Default dictionary values are provided to make most the basic job
runnable.
The CluUtil class has the following features:
Running cluster (batch mode) or XCluster
Distance matrix le generation for input into cluster
CluUtil instances are constructed to use the following by default:
ARMS heavysuperimpose, then use heavy atoms for RMSD calculation
MMSYMautomatically perceives molecular symmetry
CluUtil instances may be constructed with following attributes:
trmsarray of atom numbers to dene torsional RMSD
nrmsarray of atom numbers to dene in-place RMSD
thresha default clustering threshold
The rest of this section provides tutorial examples. The tutorial assumes an understanding of
Cluster .clu les and operation. See the MacroModel XCluster Manual for more information.
Example 1. Writing a simple .clu le
# clus_tut1.py
import schrodinger.application.macromodel.utils as mmodutil
xcu = mmodutil.CluUtil()
clu_file_name = xcu.writeCluFile('clus_tut1_confsearch-out.mae')
The default instances superimpose the structures, and use the heavy atom keyword for the
arms directive.
Example 2. Writing a .clu le with list of atom numbers
# clus_tut2.py
import schrodinger.application.macromodel.utils as mmodutil
xcu = mmodutil.CluUtil(arms=[1,2,3,4,5,6,7])
clu_file_name = xcu.writeCluFile('clus_tut2_confsearch-out.mae')
Appendix B: The MacroModel Python Package
Schrdinger Suite 2009 78
The passed atom numbers are the only atoms used for the RMSD calculation. Here, we pass an
array of nrms atom numbers, which calls for in-place RMSD calculations.
Example 3. Running a .clu le with CluUtil
# clus_tut3.py
import schrodinger.application.macromodel.utils as mmodutil
xcu = mmodutil.CluUtil()
clu_file_name = xcu.writeCluFile('clus_tut3.mae')
xcu.runCluFile(clu_file_name)
The top-level cluster executable is not run under Job Control.
B.3 The apps Module
The apps.py module contains methods to execute trivial workows.
Example 1. Converging a conformation search
Sometimes you are interested in nding an exhaustive collection of conformations for a mole-
cule. One reasonable practice for converging conformation searches is to run the search in
blocks, seeding the subsequent blocks with the results of the previous blocks. After repeating
the process a number of times without nding new conformations, the search may be taken as
approaching convergence. Also, it can be efcient to minimize conformers found during the
search with a loose criteria, then re-minimize the collection with a more stringent criteria,
throwing out redundant conformers. Separating the work into two phases may reduce the
amount of time the conformation search portion of the job spends minimizing conformers that
are discarded as new global minima are found.
# app_tut1a.py
import schrodinger.application.macromodel.apps as mmodapps
mmodapps.converge_search(mae_file='app_tut1.mae')
The converge_search() function does the following:
a. Runs 5000 Monte Carlo Multiple minima search steps, with a mild minimization conver-
gence threshold (0.05 RMSD gradient).
b. Runs a Multiple minimization on the found conformers with tighter convergence thresh-
old (0.001 RMSD gradient).
c. Counts the number of minimized conformers found.
d. Runs the next search using the minimized confs as input, and a new random number gen-
erator SEED.
Appendix B: The MacroModel Python Package
Scripting with Python 79
This procedure is repeated until a total of 5 rounds have been performed or the number of
minimized conformers found does not increase between two successive rounds and more than
3 blocks have been performed.
In the next example, the search method, number of search/multiple minimization blocks, and
the number of search steps per block are parameters for the method.
# app_tut1b.py
import schrodinger.application.macromodel.apps as mmodapps
mmodapps.converge_search(
mae_file='app_tut1b.mae',
method='LMOD',
steps=6000,
blocks=4
)
The parameters for this call to converge_search() request a low-mode search, four rounds
of search plus multiple minimization, with 6000 low-mode search steps taken in each round.
Example 2. Converging a conformation search with a custom ComUtil instance.
The converge_search() function uses the ComUtil class to prepare MacroModel .com
les and run the job. Additional keyword arguments may be supplied to create the ComUtil
instance.
# app_tut2.py
import schrodinger.application.macromodel.apps as mmodapps
mmodapps.converge_search(mae_file='app_tut2.mae', ffld='amber', solv=True)
The parameters for this call request the same process as before, but modify the ComUtil
instance to use the GB/SA solvation model and the AMBER force eld.
Example 3. Creating a representative conformer sample for a collection of
molecules
The function get_rep_confs allows you to perform a conformational search on one or more
molecules (nonconformers) then reduce the conformer collection of each molecule down to a
smaller representative set.
# app_tut3a.py
import schrodinger.application.macromodel.apps as mmodapps
mmodapps.get_rep_confs(mae_file='app_tut3a.mae')
This function does the following:
performs a serial conformation search (sets up an independent search for each member in
the le) with 5000 Monte Carlo Multiple Minima steps for each search
Appendix B: The MacroModel Python Package
Schrdinger Suite 2009 80
groups output of conformational search by serial number index into separate Maestro for-
mat structure les
performs multiple minimization of each grouped collection
reduces the output of each minimized group, with cluster, to 5 representative conformers
The function get_rep_confs uses the ComUtil class, and additional keyword arguments
may be passed to create the ComUtil instance.
# app_tut3b.py
import schrodinger.application.macromodel.apps as mmodapps
mmodapps.get_rep_confs(mae_file='app_tut3b.mae', ffld='amber', solv=True)
The parameters for this call request the same process as above, but modify the ComUtil
instance to use the GB/SA solvation model and the AMBER force eld.
Scripting with Python 81
Scripting with Python
Getting Help
Schrdinger software is distributed with documentation in PDF format. If the documentation is
not installed in $SCHRODINGER/docs on a computer that you have access to, you should install
it or ask your system administrator to install it.
For help installing and setting up licenses for Schrdinger software and installing documenta-
tion, see the Installation Guide. For information on running jobs, see the Job Control Guide.
Maestro has automatic, context-sensitive help (Auto-Help and Balloon Help, or tooltips), and
an online help system. To get help, follow the steps below.
Check the Auto-Help text box, which is located at the foot of the main window. If help is
available for the task you are performing, it is automatically displayed there. Auto-Help
contains a single line of information. For more detailed information, use the online help.
If you want information about a GUI element, such as a button or option, there may be
Balloon Help for the item. Pause the cursor over the element. If the Balloon Help does
not appear, check that Show Balloon Help is selected in the Maestro menu of the main
window. If there is Balloon Help for the element, it appears within a few seconds.
For information about a panel or the tab that is displayed in a panel, click the Help button
in the panel, or press F1. The help topic is displayed in your browser.
For other information in the online help, open the default help topic by choosing Online
Help from the Help menu on the main menu bar or by pressing CTRL+H. This topic is dis-
played in your browser. You can navigate to topics in the navigation bar.
The Help menu also provides access to the manuals (including a full text search), the FAQ
pages, the New Features pages, and several other topics.
If you do not nd the information you need in the Maestro help system, check the following
sources:
Maestro User Manual, for detailed information on using Maestro
Maestro Command Reference Manual, for information on Maestro commands
Maestro Overview, for an overview of the main features of Maestro
Maestro Tutorial, for a tutorial introduction to basic Maestro features
Frequently Asked Questions pages on the Schrdinger Support Center.
Known Issues pages, available on the Support Center.
Getting Help
Schrdinger Suite 2009 82
The manuals are also available in PDF format from the Schrdinger Support Center. Local
copies of the FAQs and Known Issues pages can be viewed by opening the le
Suite_2009_Index.html, which is in the docs directory of the software installation, and
following the links to the relevant index pages.
Information on available scripts can be found on the Script Center. Information on available
software updates can be obtained by choosing Check for Updates from the Maestro menu.
If you have questions that are not answered from any of the above sources, contact Schrdinger
using the information below.
E-mail: help@schrodinger.com
USPS: Schrdinger, 101 SW Main Street, Suite 1300, Portland, OR 97204
Phone: (503) 299-1150
Fax: (503) 299-4532
WWW: http://www.schrodinger.com
FTP: ftp://ftp.schrodinger.com
Generally, e-mail correspondence is best because you can send machine output, if necessary.
When sending e-mail messages, please include the following information:
All relevant user input and machine output
Schrdinger Suite purchaser (company, research institution, or individual)
Primary Schrdinger Suite user
Computer platform type
Operating system with version number
Version numbers of products installed for Schrdinger Suite
Maestro version number
mmshare version number
On UNIX you can obtain the machine and system information listed above by entering the
following command at a shell prompt:
$SCHRODINGER/utilities/postmortem
This command generates a le named username-host-schrodinger.tar.gz, which you
should send to help@schrodinger.com. If you have a job that failed, enter the following
command:
$SCHRODINGER/utilities/postmortem jobid
where jobid is the job ID of the failed job, which you can nd in the Monitor panel. This
command archives job information as well as the machine and system information, and
includes input and output les (but not structure les). If you have sensitive data in the job
Getting Help
Scripting with Python 83
launch directory, you should move those les to another location rst. The archive is named
jobid-archive.tar.gz, and should be sent to help@schrodinger.com instead.
If Maestro fails, an error report that contains the relevant information is written to the current
working directory. The report is named maestro_error.txt, and should be sent to
help@schrodinger.com. A message giving the location of this le is written to the terminal
window.
More information on the postmortem command can be found in Appendix A of the Job
Control Guide.
On Windows, machine and system information is stored on your desktop in the le
schrodinger_machid.txt. If you have installed software versions for more than one
release, there will be multiple copies of this le, named schrodinger_machid-N.txt,
where N is a number. In this case you should check that you send the correct version of the le
(which will usually be the latest version).
If Maestro fails to start, send email to help@schrodinger.com describing the circumstances,
and attach the le maestro_error.txt. If Maestro fails after startup, attach this le and the
le maestro.EXE.dmp. These les can be found in the following directory:
%USERPROFILE%\Local Settings\Application Data\Schrodinger\appcrash
Schrdinger Suite 2009 84
120 West 45th Street, 17th Floor
New York, NY 10036
101 SW Main Street, Suite 1300
Portland, OR 97204
8910 University Center Lane, Suite 270
San Diego, CA 92122
Zeppelinstrae 13
81669 Mnchen, Germany
Dynamostrae 13
68165 Mannheim, Germany
Quatro House, Frimley Road
Camberley GU16 7ER, United Kingdom
SCHRDINGER

Você também pode gostar