Sunteți pe pagina 1din 94

Scripting with Python

Scripting with Python


Schrdinger Suite 2008

Schrdinger Press

Scripting with Python Copyright 2008 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, September 2008

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

Scripting with Python

iii

Contents

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 iv Schrdinger Suite 2008

Contents

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

Scripting with Python

Contents

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

vi

Schrdinger Suite 2008

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.
Font Sans serif Monospace Italic Sans serif uppercase Example Project Table $SCHRODINGER/maestro lename CTRL+H Use Names of GUI features, such as panels, menus, menu items, buttons, and labels File names, directory names, commands, environment variables, and screen output Text that the user must replace with a value Keyboard keys

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 conventions. 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].

Scripting with Python

vii

viii

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 1

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_2008_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.5.1 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

Scripting with Python

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 2

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 interpreted 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 modules1 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.org1 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 2008 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 Python1 is lled with valuable, graduated examples that will help you master Python. If you are a more experienced user, Thinking in Python1 covers more advanced concepts like applying design patterns to Python. O'Reilly1 has published a number of popular Python books. The Vaults of Parnassus1 contain many useful Python modules and examples.
1. Please see the notice regarding third party programs and third party Web sites on the copyright page at the front of this manual.

Scripting with Python

Chapter 2: About Python

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 essentials 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:

Schrdinger Suite 2008

Chapter 2: About Python

# 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 recognize 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.

Scripting with Python

Chapter 2: About Python

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?2 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 insignicant relative to the work done by Maestro to execute the commands sent to it from a Python script.

2.

Please see the notice regarding third party programs and third party Web sites on the copyright page at the front of this manual.

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 3

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 controlling 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 individual 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 generated 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 WorkScripting with Python 7

Chapter 3: Running Python Within Maestro

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 therefore the properties are not accessible via the Workspace structures. It is also important to understand that entries (structures) that have been modied in the Workspace 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 structural 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 maintaining 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.

Schrdinger Suite 2008

Chapter 3: Running Python Within Maestro

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.

Scripting with Python

Chapter 3: Running Python Within Maestro

Figure 3.1. Import Error.

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.2. Indentation Error.


10 Schrdinger Suite 2008

Chapter 3: Running Python Within Maestro

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

Scripting with Python

11

Chapter 3: Running Python Within Maestro

Python scripts to be very general. For example, you can write a script that operates on a lename 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"
12 Schrdinger Suite 2008

Chapter 3: Running Python Within Maestro

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.

Scripting with Python

13

14

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 4

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.

Scripting with Python

15

Chapter 4: Issuing Maestro Commands

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.
16 Schrdinger Suite 2008

Chapter 4: Issuing Maestro Commands

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 parameters, 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:
Scripting with Python 17

Chapter 4: Issuing Maestro Commands

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
18 Schrdinger Suite 2008

Chapter 4: Issuing Maestro Commands

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 module 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 combination 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.

Scripting with Python

19

20

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 5

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 collection 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()

Scripting with Python

21

Chapter 5: Manipulating the Workspace

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:

22

Schrdinger Suite 2008

Chapter 5: Manipulating the Workspace

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 Maestro atom name (used for Jaguar mostly) Molecular representation of the atom (wire, CPK etc.) MacroModel atom type Atomic number PDB chain name Integer index representing color in Maestro color palette Formal charge Maestro builder grow name PDB residue insertion code Partial atomic charge PDB atom name PDB residue name PDB residue number Secondary structure assignment (HE-) Solvation atomic charge PDB temperature factor (isotropic B factor) Workspace display state x coordinate List of atomic coordinates [x, y, z] y coordinate z coordinate

atom_name atom_style atom_type atomic_number chain color formal_charge growname inscode partial_charge pdbname pdbres resnum secondary_structure solvation_charge temperature_factor visible x xyz y z

Scripting with Python

23

Chapter 5: Manipulating the Workspace

Table 5.2. Atom properties for access only - cannot be modied. Property atomic_number Description Atomic number of the atom. Atomic weight of the atom. If implicit hydrogens are present, they are included as part of the atomic weight. Total number of bonds to this atom An iterator that returns atoms bonded to this atom Chirality of the atom: R, S, or None. Element symbol Entry ID 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 (atom number) of the atom in the structure, ignoring any classication into molecule, entry, and so on. Number of the molecule to which this atom belongs Atom number by entry Atom number by molecule

atomic_weight bond_total bonded_atoms


chirality

element entry_id entry_name

index

molecule_number number_by_entry number_by_molecule

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

24

Schrdinger Suite 2008

Chapter 5: Manipulating the Workspace

This example uses the bond order property. The available bond properties are listed in Table 5.3.
Table 5.3. Bond properties for access or modication. Property Description Bond order The rst atom of the bond The second atom of the bond The molecular representation of the bond (wire, tube)

order atom1 atom2 style

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 peformed between different Structure objects and also supports determining the angle between two planes (as dened between two sets of three atoms).

Scripting with Python

25

Chapter 5: Manipulating the Workspace

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.
26 Schrdinger Suite 2008

Chapter 5: Manipulating the Workspace

5.5

Iterating Over Objects in the Structure

It is possible to iterate over a number of objects in a Structure objectchains, molecules, residues 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 iterators. 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 Workspace structure. We use a Python function to highlight close contacts between any atoms separated 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 :

Scripting with Python

27

Chapter 5: Manipulating the Workspace

# 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 additional 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 expression: 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!
28 Schrdinger Suite 2008

Chapter 5: Manipulating the Workspace

#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:

Scripting with Python

29

Chapter 5: Manipulating the Workspace

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

30

Schrdinger Suite 2008

Chapter 5: Manipulating the Workspace

# 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

Scripting with Python

31

Chapter 5: Manipulating the Workspace

# 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.

32

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 6

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()

Scripting with Python

33

Chapter 6: Scripting the Project Table

# 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.

34

Schrdinger Suite 2008

Chapter 6: Scripting the Project Table

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 properties 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 corresponding 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 ):

Scripting with Python

35

Chapter 6: Scripting the Project Table

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.

36

Schrdinger Suite 2008

Chapter 6: Scripting the Project Table

#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(): """

Scripting with Python

37

Chapter 6: Scripting the Project Table

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

38

Schrdinger Suite 2008

Chapter 6: Scripting the Project Table

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:

Scripting with Python

39

Chapter 6: Scripting the Project Table

# 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()

40

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 7

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 moduel 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:

Scripting with Python

41

Chapter 7: Running Jobs from Scripts

( 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 function.

42

Schrdinger Suite 2008

Chapter 7: Running Jobs from Scripts

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 information 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 specialvalue. 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 incorporated. 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 incorporation. The callback is called by Maestro for every job that is incorporatable. The callback must therefore 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.
Scripting with Python 43

Chapter 7: Running Jobs from Scripts

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 paramater 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 incorporated 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-0434ac660 and are printed to the output of all Schrdinger jobs.

44

Schrdinger Suite 2008

Chapter 7: Running Jobs from Scripts

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)

Scripting with Python

45

Chapter 7: Running Jobs from Scripts

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]

46

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 8

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.

8.1

Tkinter

We support the Tkinter graphical user interface (GUI) toolkit for Python. It is simple to use and comes as a standard part of Python. This document 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 information on using Tkinter, see the recommended OReilly books on Python3 or the following page on the Pythonware website3 which offers a step-by-step tutorial. For information on PMW, see http://pmw.sourceforge.net3. You can also nd more examples using Maestro and Tkinter at: $SCHRODINGER/python-vversion/scripts/maestro/

8.2

Important Considerations

When a Tkinter program is running within Maestro both programs need to share event information. 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.
3. Please see the notice regarding third party programs and third party Web sites on the copyright page at the front of this manual.

Scripting with Python

47

Chapter 8: Writing Your Own Panels

Note:

Any number of Python/Tkinter scripts can be sharing events with Maestro.

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.3

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

48

Schrdinger Suite 2008

Chapter 8: Writing Your Own Panels

opened from the main Maestro menu) then your panel loses the ability to receive selection 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)

Scripting with Python

49

Chapter 8: Writing Your Own Panels

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(). 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.4

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()

50

Schrdinger Suite 2008

Chapter 8: Writing Your Own Panels

maestro.tk_toplevel_add(simple_top)

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.5

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/mae80_help, for all products. The topics themselves are in subdirectories, but you can store your own topic wherever you like in this directory. 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. You will have to set the environment variable SCHRODINGER_MAESTRO_HELP to myhelpdir before you start Maestro in order to use your copy of the help. 2. Choose a topic ID, and add the ID and the relative URL to the le help_map_file. This le is in $SCHRODINGER/docs/maestro/help/mae80_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 $SCHRODINGER/docs/maestro/help/mae80_help. 3. Add these Maestro commands to the code for the action of your Help button: maestro.command("helptopic MY_TOPIC_ID") maestro.command("showpanel help") For more information on customizing the help, see Appendix E of the Maestro User Manual.

Scripting with Python

51

52

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 9

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");

Scripting with Python

53

Chapter 9: Registering Python Functions with Maestro

When you issue the pythonrun spin.start_spin command, the contents of the Workspace 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))

54

Schrdinger Suite 2008

Chapter 9: Registering Python Functions with Maestro

_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 thatindicates 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():

Scripting with Python

55

Chapter 9: Registering Python Functions with Maestro

# 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)

56

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 10

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.org4. 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


4. Please see the notice regarding third party programs and third party Web sites on the copyright page at the front of this manual.

Scripting with Python

57

Chapter 10: Debugging Your Scripts

if axis != "y" and axis != "x" and axis != "z" : raise Exception, "Can't use axis: " + axis 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 website5.

5.

Please see the notice regarding third party programs and third party Web sites on the copyright page at the front of this manual.

58

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 11

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 directory 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
Scripting with Python 59

Chapter 11: The Maestro Scripts Menu

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. This looks like: __doc__= """ A description of the script Author Date """ This doc string will be 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.
60 Schrdinger Suite 2008

Chapter 11: The Maestro Scripts Menu

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.

Scripting with Python

61

62

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 12

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 situations.) 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 terminal 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__':

Scripting with Python

63

Chapter 12: Tips and Traps

#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/utilities/run pdbname.py inle outle Imported into another module: import pdbname

64

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Chapter 13

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 variables are set up before your script is run. You can run Python scripts using this version with the command $SCHRODINGER/utilities/run. $SCHRODINGER/run is most commonly used to run a script that is located in the local directory 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 2008 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 locations, 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.
Scripting with Python 65

Chapter 13: Running Scripts Outside Maestro

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 structures 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: .ent .pdb .sd .sdf .mol .mol2 .mae.gz .maegz .mae PDB SD

Tripos mol2 Gzip compressed Maestro Maestro

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)

66

Schrdinger Suite 2008

Chapter 13: Running Scripts Outside Maestro

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/utilities/run findcl.py inle.mae outle.mae
Note:

In this case, the format is specied explicitly as format=maestro so this only operates 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: r_user_ i_user_ s_user_ b_user_

Real number Integer String Boolean

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 Scripting with Python 67

Chapter 13: Running Scripts Outside Maestro

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)

68

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Appendix A

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
application graphics3d infra

Description Application-specic functions Support for drawing in the Workspace Low-level package with tools not intended for general script usage. We reserve the right to change these modules as we feel necessary. Functions for launching and managing jobs Functions used for interaction with Maestro Functions used with Maestro projects, either inside or outside Maestro Package for capping, analyzing, and adding hydrogens to proteins. Functions to read, write, and manipulate structures Functions that operate on structure objects: nding rings and matching SMARTS expressions, etc. Package for modules of structure utilities 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. Utility functions - logging script operations and standardized processing of command line options.

job maestro project protein structure structureutil

structutils ui

utils

Scripting with Python

69

70

Schrdinger Suite 2008

Schrdinger Suite Scripting with Python


Appendix B

Appendix B:

The MacroModel Python Package

MacroModel is a force-eld based, molecular mechanics program. The input for a MacroModel 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 dictionary. 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

Scripting with Python

71

Appendix B: The MacroModel Python Package

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 calculation is created. The last line writes the .com le. As each opcode is written to the le, the arguments 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 BDCO 0 FFLD 14 READ 0 ELST -1

5 0 0 0 0

0 0 0 0 0

0 0 0 0 0

8.0000 20.0000 0.0000 99999.0000 1.0000 0.0000 0.0000 0.0000 0.0000 0.0000

4.0000 0.0000 0.0000 0.0000 0.0000

8.0000 0.0000 0.0000 0.0000 0.0000

72

Schrdinger Suite 2008

Appendix B: The MacroModel Python Package

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 documentation for a description of the methods.
# 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.
# 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 minimization method and the convergence criteria are altered rst, then the .com le is written.

Scripting with Python

73

Appendix B: The MacroModel Python Package

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 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 electrostatic 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 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"

is

with

the

74

Schrdinger Suite 2008

Appendix B: The MacroModel Python Package

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 MacroModel 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],

Scripting with Python

75

Appendix B: The MacroModel Python Package

'-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 commandline equivalent is: $SCHRODINGER/bmin mmod_tut6 -HOSTFILE mmod_tut6.hst

76

Schrdinger Suite 2008

Appendix B: The MacroModel Python Package

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

How it works 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 followingfeatures: 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])

Scripting with Python

77

Appendix B: The MacroModel Python Package

clu_file_name = xcu.writeCluFile('clus_tut2_confsearch-out.mae')

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 jobcontrol.

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 molecule. 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 convergence threshold (0.05 RMSD gradient). b. Runs a Multiple minimization on the found conformers with tighter convergence threshold (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 generator SEED.
78 Schrdinger Suite 2008

Appendix B: The MacroModel Python Package

This procedure is repeated until a total of 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

Scripting with Python

79

Appendix B: The MacroModel Python Package

groups output of conformational search by serial number index into separate Maestro format 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.

80

Schrdinger Suite 2008

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 documentation, 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 Help 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. The help topic is displayed in your browser. For other information in the online help, open the default help topic by choosing Help from the Help menu on the main menu bar or by pressing CTRL+H. This topic is displayed in your browser. You can navigate to topics in the navigation bar. 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.

The manuals are also available in PDF format from the Schrdinger Support Center. Information on additions and corrections to the manuals is available from this web page.

Scripting with Python

81

Getting Help

If you have questions that are not answered from any of the above sources, contact Schrdinger using the information below. E-mail: USPS: Phone: Fax: WWW: FTP: help@schrodinger.com Schrdinger, 101 SW Main Street, Suite 1300, Portland, OR 97204 (503) 299-1150 (503) 299-4532 http://www.schrodinger.com 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 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. 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,
82 Schrdinger Suite 2008

Getting Help

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, you can copy the information from the DOS window from which Maestro was launched. To do so, use the window manager menu (in the top left corner of the window): point to Edit, then Select All, and press ENTER. The text is now in the buffer and can be pasted into a message.

Scripting with Python

83

84

Schrdinger Suite 2008

120 West 45th Street 29th Floor New York, NY 10036

101 SW Main Street Suite 1300 Portland, OR 97204

3655 Nobel Drive Suite 430 San Diego, CA 92122

Dynamostrae 13 68165 Mannheim Germany

QuatroHouse, Frimley Road Camberley GU16 7ER United Kingdom

SCHRDINGER

S-ar putea să vă placă și