Contents
Why?
This guide is for ICM users who want to learn how to create or understand software written in ICM’s full-featured scripting language. This guide is not a comprehensive reference of the full capabilities of ICM and its scripting language but it is designed to provide a good overview of the topics important to someone with some general programming experience who wishes to take advantage of ICM’s programmability.
Usage
Interpreter Considerations
When creating non-interactive scripts in the ICM scripting language,
you must use the correct program loader directive. This must reflect a
path to your ICM executable. It may be reasonable if the program is to
run autonomously to call ICM without the overhead of a graphical user
interface. This is done with icmng
. The following is a typical
useful first line for ICM script files:
#!/usr/local/bin/icm/icmng -s
Note
|
In the lab, our path is /pro/icm/icm/ or if you’re trying
to emphasize stability try /pro/icm/icms/ . |
The -s
option stands for "silent" because it suppresses all of the
start up messages.
Version
To find out what version of ICM you are using you can use the following features:
icm/def> show version
Info> icm version
3.7-3a/Lin-iX86-64bit/g4.4/Release/HardwareGL/Gui263940/WebKit/Video/FlexLM
[Jan 18 2013 17:10], path="/pro/icm/icm/icm" UNIX BCDZEHPQRXUVM
icm/def> Version()
3.7-3a/Lin-iX86-64bit/g4.4/Release/HardwareGL/Gui263940/WebKit/Video/FlexLM/icm
UNIX BCDZEHPQRXUVM
If you’re in an environment where the ICM is updated frequently, it is often useful to consider the date in the version string as this is when this ICM executable was actually compiled.
Interpreter Initialization
When ICM starts, it loads a lot of files. These include system-wide
and user-specific start-up files, as well as special files in the ICM
home directory (like _macro
and icm.*
).
Moreover, ICM is controlled by preferences. Users may have non-default preferences that are stored and loaded from their home directory. Adding to the complexity is the fact that specific paths and the exact list of loaded files depends on (1) the ICM command line options, (2) the version of ICM, and (3) the operation system.
On Linux, the following locations can contain special user-specific functionality.
~/.icm
~/.molsoft
~/.browser
~/.browerpro
~/.qt <= This is non-trivial.
Interactive
When using ICM’s command line interactively, you will see icm/def>
.
This prompt is defined with the s_icmPrompt
variable. It can be set
with things like %t>
which will show the elapsed time since this
shell was started, like this:
icm/def> s_icmPrompt = "%t>"
00:00:27>
What does def
in icm/def>
mean? Not really sure.
When an object is specified by itself in the shell, the interpreter evaluates and prints object’s value (like the Python interpreter). This can be handy for debugging.
Style
Literal Interpretation
The ICM scripting language usually does not need to decorate variables
to indicate that is what they are (like Bash and Perl do with $
). It
adds defined variables to the correct name space and evaluates them
when the name is encountered. However, ICM also allows for explicit
variable evaluation. For example:
icm/def> a ="b" ; s="a"
icm/def> print s $s
a b
Don’t get too carried away with this or you’ll get an error like:
Warning> [1] $expressions will not be evaluated in substituted $variables
Formatting
Semi-colons can be used to separate commands (since version 3.6-1). They are not required to terminate a statement. Note that the interpreter’s history mechanism will store multiple statements separated by semi-colons as multiple history entries. This differs from other interpreted shells such as Bash or Python. It probably is wise to avoid using semi-colons.
Space is an important delimiter. If you do something like this:
x="*"
print x # Returns "*"
print x x # Returns "* *"
print xx # Error if variable xx is not defined!
print x+x # Returns "**"
Although space is important here, it’s not as important as it might seem. For example:
print x x # Returns "* *"
In general you can put as many spaces as you like as a delimiter.
Comments
At the beginning of a line, a #
character causes the interpreter to
ignore the following comment. In the middle of a line the #
causes
the interpreter to ignore subsequent text allowing for comments like:
x="*" # A star is born.
Interestingly in ICM’s shell history a comment is not even recorded, so making notes to yourself in interactive sessions for history recall probably won’t work.
Naming Conventions
ICM commands tend to use all lower case letters (example delete
).
ICM’s built in functions tend to capitalize the first letter of the
function (example Nof()
). ICM macros tend to use what Perl people
call "camel case" where the name is descriptively several concatenated
words with each capitalized (example MakePdbFromStereo
).
Types
ICM’s scripting language has many types here are some of the important ones with their official abbreviations:
|
integer |
|
real |
|
string |
|
logical |
|
iarray |
|
rarray |
|
sarray |
|
matrix |
|
sequence |
|
profile |
|
alignment |
|
map |
|
graphics object (grob) |
|
selections of internal coordinates (for example torsion angles) |
|
table |
|
table array of integers |
|
table array of reals |
|
table array of strings |
There are types involving selections that can get quite complex:
os_
::object selection
ms_
::molecule selection
rs_
::residue selection
as_
::any kind of selection (object/molecule/residue/atom); in some cases means only atom selection
aselection
:: generic type of os_
, ms_
, rs_
and as_
There are some other types which do not necessarily have official
abbreviations: vselection
, command
, macro
There may be more.
Assignment
For simple object usage, things are simple:
Assign an integer:
a=1
Assign a real:
b=1.
Assign a character (string) type:
c="a string"
ICM’s scripting language is pretty strongly typed for a scripting language. In Perl or Python a variable can contain one type and then be reassigned to a different type implicitly casting it to that new type. ICM does not force you to explicitly declare a variable’s type but it does require that you be consistent with it as the following example shows:
icm> a=3
icm> a="*"
Error> [696] wrong assignment or name conflict
icm> delete a
icm> a="*"
icm> print a
*
It is possible to convert variables in place if there is sufficient information. For example:
icm/def> aninteger=1
icm/def> aninteger=2.1
Error> [696] wrong assignment or name conflict
icm/def> afloat=2.1
icm/def> afloat=1
icm/def> print afloat
1.
In this case it was possible to make the 1
into a 1.0
but ICM
didn’t want to make the 2.1
into a 2
automatically.
If you want to see all of the integers that are defined, you can use
show integer
. This works for string
, real
, map
, and others.
Casting
If you need to explicitly work with a variable’s type you can use one of the many functions provided for this:
- Integer()
-
Converts function argument to an integer type.
- Tointeger()
-
A (redundant?) function similar to
Integer()
? - Iarray()
-
Converts an array of non-integers to an array of integers if possible.
- Real()
-
Converts function argument to a real type.
- Toreal()
-
A (redundant?) function similar to
Real()
? - Rarray()
-
Converts to a real array if possible.
- String()
-
Converts function argument to a string type.
- Tostring()
-
A (redundant?) function similar to
String()
? - Sarray()
-
Converts to a string array if possible.
- Type()
-
Returns the type of an object.
- Table()
-
A very versatile function that produces various table objects.
- Grob()
-
A versatile function to generate graphics objects.
Shell Variables
One property of ICM that is somewhat idiosyncratic is that many
functions, in addition to possibly handling input and output, also set
internal ICM shell variables which can be used in subsequent
operations. This is a bit like the Perl variable $_
which is
magically set after certain functions run, allowing subsequent
functions to assume some preparatory action (or as the Perl people
say, "underline is understood to be underlying certain undertakings").
In ICM the following automatic variables are sometimes set by functions and can be used by subsequent operations.
i_out , i_2out , r_out , l_out , s_out , R_out , as_out
Apparently you can modify these variables with some caveats. You can not delete them. Also functions will overwrite anything you put in there if given a chance.
Strings
Strings can be defined in a few ways. You can use quotes pretty intuitively:
x='a string'
y="also a string"
z="ICM's strings"
You can also use a Python style triple quote style like this:
icm/def> Gmaj="""3
?> 0
?> 0
?> 0
?> 2
?> 3"""
icm/def> print Gmaj
3
0
0
0
2
3
ICM has escape sequences for several common symbols like \"
, \t
,
\n
.
Strings can be treated like arrays to an extent. You can do something like this similar to Python slices:
icm/def> t='abc'
icm/def> print t[2]
b
icm/def> print t[1:2]
ab
Strings can be formatted the C way with the printf command. To just format the string without printing it per se, see sprintf. To send formatted string output to a file, see fprintf (also see the IO section below).
Functions To Work With Strings
-
+
-
Concatenates two strings. Sometimes, as with the
print
command, if strings are arguments, they get concatenated automatically. Best not to rely or base a programming style on that. -
Field()
-
Extracts a particular field (as in a text database) from a line of text. The line of text must have the fields delimited in some sensible way. Here’s an example with comma separated values: If
iron= "Fe,[Ar] 3d6 4s2,26"
thenField(iron,3,',')
is "26". Without the third (separator argument) the assumption is whitespace. -
Index()
-
Returns position of specified substring ("cd") in specified string ("abcdefg").
Index('abcdefg', 'cd')
returns 3. With an optional third argumentlast
, the position of the last occurrence is returned. If the optional third argument is a positive number it starts the search after that position. If it’s a negative number it searches the end. For example, to check for the presence of a file name extension,Index(fn,'gz',-2)
. This will return a positive number if it ends in gz. -
Length()
-
Returns how long a string is. This is useful for iterating over each character and tasks like that. Many things in ICM use
Nof()
but not strings. -
Match()
-
Returns anything in the first (string) argument that matches the second argument’s regular expression. For example, this finds a valid looking (but possibly out of range) IP address:
Match('192.168.33.132', '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}')
-
Replace()
-
Replace occurrences of the second argument in the first with the third. For example
Replace('grace','g','rat')
produces "ratrace". Fancier things are possible too such asReplace('Miss Smith', {'Miss','Mrs.'}, 'Ms.')
. Regular expressions can be used too. -
Split()
-
To cut a string into parts. This returns a string array. For example:
Split('alice&bob&eve','&')[2]
returns "bob". To just get a string array of all the letters, make the character to split upon empty (""). -
Tolower()
-
Converts strings to lower case.
-
Tostring()
-
Converts other types to a string.
Tostring( (1==1) )+"=true"
produces "yes=true". -
Toupper()
-
Converts strings to upper case.
-
Trim()
-
Removes trailing whitespace from a string.
'x' + Trim(' abcde ' ) + 'x'
returnsx abcdex
. Note that only the end is trimmed. However, with a second argument,all
both ends are trimmed. If the second argument is a string, only the letters in the second argument are preserved from the string. SoTrim("$45US",'0123456789')
produces45
. -
Type()
-
For strings, returns the string "string". Helpful to make sure you really are working with a string.
Arrays
Arrays are ordered containers of consistently typed objects.
a={1,2,3}
Nof(a) # Function to return "Number of"
3
delete variable a 2 # deletes second value of the array `a`.
Nof(a)
2
The command list
is used to "display" variables, i.e. not for
anything related to an itemized list in the Python or Lisp sense.
icm/def> list wireStyle
wireStyle = "chemistry"
With no arguments, it will give you a list of defined variables.
ICM has a type of array that points to other types of objects. This is
a "pointer array", the parray
type. This allows you to store
heterogeneous typed objects in one object.
Tables
The first thing to clarify is that there exist "predefined icm-shell tables" (described here) which are not "user-defined ICM tables" (described here). Just be aware that sometimes tables are referred to (the "Tables" link on the molsoft.com/man page) and they don’t mean the kind you’ll typically use. That said, many ICM features like to generate a table object that the user can use.
Tables are not simply two dimensional arrays. Tables are a first class data type that contain and organize arrays of other types. A table is a specific data structure that may have zero or more columns (arrays with data) and zero or more headers (which also may be arrays).
You can check to see if an ICB file contains a table and what that table’s name is with this.
icm/def> list binary "myfile.icb"
Binary file version: 16
1 msLigandModelAll table 13599724 0
icm/def> read binary list name="msLigandModelAll" "myfile.icb"
Info> 1 objects from myfile.icb kept in msLigandModelAll
The most basic way to create a table is to use group table
. This
takes at least one argument which comes next and must be the name of
the table.
icm/def> group table an_empty_new_user_table
Info> table an_empty_new_user_table (0 headers, 0 arrays) has been created
Headers:
Arrays :
icm/def> Type(an_empty_new_user_table)
table
To verify that you have created a table or to find your table after
forgetting what you named it, use list tables
. You’ll notice that
there are many built in tables in ICM.
The next thing to do is to add "columns" to the table. This can be
with the group table
command.
icm/def> group table t {10,20,30} "tens" {1,2,3} "ones"
Info> table t (0 headers, 2 arrays) has been created
Headers:
Arrays : t.tens t.ones
icm/def> t
#>T t
#>-tens--------ones-------
10 1
20 2
30 3
icm/def> Type(t)
table
icm/def> Type(t.ones)
iarray
Columns can also be added with the add column
command. This also can
create empty tables. Here’s an example of both.
icm/def> add column abc
Info> 0 columns '' added to table 'abc'
icm/def> add column abc {'A' 'B' 'C'} name="column_name_here"
Info> 1 column 'column_name_here' added to table 'abc'
icm/def> show abc
#>T abc
#>-column_name_here
A
B
C
If working with tables interactively, you can invoke the system’s text
editor and make arbitrary edits to tables with the following command:
edit t
group table t {1 2 3} "a" {4. 5. 7.} "b"
delete t.a == 2 # the second entry
show t
delete t[2] # the second entry
show t
delete t # the whole thing
group table t {1 2 3} "a" {4. 5. 7.} "b"
delete t.a > 1 # 2nd and 3rd
You can also change the value of individual cells with a command like:
icm/def> t.a[1] = 0
Accessing Table Elements
To access individual table components, you can use t.a[1]
if you
know and can explicitly name the cell. However to iterate over all the
cells can be a bit trickier.
Here’s the problem:
icm/def> Ufields=Name(atable)
icm/def> Ufields[3]
atable.SM
icm/def> Type(Ufields[3])
string
icm/def> Type(atable.SM)
sarray
This means that to iterate over the table’s values, you need to do something like this:
Ufields=Name(atable)
for i=1,Nof(Ufields)
s_col = Ufields[i]
for j=1,Nof( $s_col )
$s_col [j] # row=i, col=j
endfor
endfor
Here is another recommended way:
Ufields=Field(Name(atable) 2 '.' )
for i=1,Nof(atable)
row = Collection( atable[i] )
for j=1,Nof( Ufields )
row[ Ufields [j] ]
endfor
endfor
Hash/Collection Objects
FAQ: What’s a "map"? A hash like C+\+? An electron density map?
It looks like there is a type
collection
. There is
documentation on this and on my ICM they seem to work, but there are
also references which make it seem like "collections" are being
renamed into "hash" objects. However ER says that "collection" is
official and correct and "hash" was some intermediate version.
To use them do something like the following:
icm/def> myattribs="{'width':'100','height':'200'}"
icm/def> c=Collection(myattribs )
icm/def> c
{
"height": "200",
"width": "100"
}
icm/def> c['width']
100
FAQ: How do you iterate over the keys in a collection? Answer:
c = Collection( "aaa","bbb" )
S_keys = Name( col )
for i=1,Nof(S_keys)
print c[ S_keys[i] ]
endfor
How to tell if an object is a key in a collection (Basically
obj.has_key(key)
in Python.)?
if ( Index(Name(P_myCollection),'PossibleKey')) then
print "Yes, that's a key."
endif
Apparently Collection(web)
is a facility for parsing CGI input but I
am still trying to figure out how. Eugene says, "It checks
REQUEST_METHOD
first, then either parses QUERY_STRING
for GET or
stdin for POST."
To use collections as function parameters, you need to name the
parameter something like: P_MyCollection
.
Clearing State
When scripting with ICM it is sometimes desirable to reset the values
of all the objects (variables, molecular objects, tables, etc) without
having to exit or restart the session. The delete all
command will
remove everything you created except for protected items (set
property delete off/on
). This is extremely useful in processing
multiple ICB files, a task that ICM scripting frequently performs.
Operators
Logical Operators
-
&
-
Logical and - "yes & no" equals "no", "yes & yes" equals "yes"
-
|
-
Logical or - "no | no" equals "no", other combinations equal "yes"
-
!
-
Logical not - "no | !yes" equals "no"
Assignment
+=
Assign result of right hand operator and left hand value to left
hand operator. a+=3
is the same as a=a+3
. The same is true for
subtraction -=
, multiplication *=
, and division /=
.
There is also an in place assignment operator can assign an array concatenation:
t.Name//="new_item"
This usage may not be robust and you may be asking for an Error 4127
when you try to append a column to a table. Needs some more
experimentation perhaps.
"//" This is a concatenation operator. This makes a rarray (an array of reals): b=3.0//4.1//5.2
The copy
operator is used for molecular objects. Normal assignment
is fine for normal variables, but molecular objects should,
apparently, be created explicitly with the copy command.
Comparison
The logical operator for testing if something is the same as something
else is ==
. To test if it’s not the same use !=
. Also inequality
operators work as expected: <
, >
, <=
, >=
.
That all sounds reasonable, but Andrey points out that there can be odd exceptions. For example, in a fresh ICM session the following behavior is observed:
icm/def> if (Nof(Obj(a_*.) ) == 0) print "there is no object"
icm/def> if (Nof(Obj(a_*.) ) != 0) print "there is at least one object"
icm/def>
Arithmetic Expressions
http://www.molsoft.com/man/arithmetics.html
All the normal algebraic operators work, +
, -
, *
, /
. Note
that, like Python, the result of dividing two integers is an integer.
This can produce unexpected results:
icm> 3.0/4 - 3/4
0.75
This happens because 3/4
(both integers) equals 0
which is 0.75
with the decimal (non integer) part discarded.
Arrays do not handle simple arithmetic operators like you might
expect. If +
concatenated two arrays, what would /
do? Instead,
when arithmetic operators are used on arrays, a new array is formed by
the operation being performed on each value of the array (in order).
This allows for things like this:
icm> a={1,2,3}; b={2,3,4}
icm> b-a
#>I
1
1
1
Note that if you want array concatenation, you can do that with the
//
operator.
Pattern Matching
- *
-
matches any string including an empty string (e.g.
*see*
) - ?
-
matches any single character (e.g.
???ee M
) - [string]
-
matches any one of the enclosed characters. Two characters separated by dash represent a range of characters. Examples:
[A-Z]
,[a-Z]
,[a-z]
,[0-9]
(e.g.[A-Z] see [A-Z]
) - [ !string]
-
negation. matches any but the enclosed characters (e.g.
I see [!K]
) - {}
-
single-character multiplication, character{m,n} (e.g.
I?\{3,6\}M
- repeat any character, ?, from 3 to 6 times)
There are also operators for pattern matching, ~
and !~
. Here’s an
example:
icm> somesa.Name={"white","knight","fights","windmills"}
icm> print (somesa.Name ~ "*gh*") // (somesa.Name !~ "*gh*")
knight fights white windmills
Regular expressions
Regular expressions can be used with the functions Match()
,
Replace()
, Index()
, Split()
Actually, ICM has several different kinds of regular expressions in
different functions and selections. for instance, the Replace
function recognizes two different sorts of expressions and its
behavior is controlled by the regexp
keyword. Sometimes we have to
create multiple escape sequences to make selections work, e.g.
Index(S_ Replace(s_ "([[*(+.+)?]])" "\\\\\\1" regexp) regexp all)
Control Structures
Branching
if
Conditional statements aren’t too confusing but there are (at least) a couple of modes to consider. First is a single line type of thing like:
if (Random() < 0.5) print "Tails"
The more complete construction is something like this:
if (Random() < 0.5) then
print "H"
elseif (Random() == .5) then
print "Lands on edge!"
else
print "T"
endif
You can omit the elseif
and/or else
clauses as necessary.
An important consideration when using if
statements is the nature of
the conditional expression. This must evaluate to a "logical" type
which can take the value yes
or no
, both reserved words for
signifying this.
icm/def> A= yes
icm/def> A
yes
icm/def> if ( A ) print "OK"
OK
Iteration
The normal way to iterate is to iterate over a range using a for
statement.
icm> for i=1,5
icm> print i
1
icm> endfor
2
3
4
5
I don’t know if there are direct ways to iterate over the items in an array, but there are definitely techniques to achieve that effect which are commonly used:
somestuff={'alpha','bravo','charlie','delta'}
for i=1,Nof(somestuff)
print somestuff[i]
endfor
While
It seems that ICM does not have a do-while type of control structure.
The conditional expression of a while
statement is always evaluated
before any of the body is executed. Under ideal circumstances, that
looks like:
while ( Random() < 5.0/6.0 )
print "Still playing Russian roulette!"
endwhile
To get a do-while effect the commonly used idiom looks like this:
#!/pro/icm/icms/icmng64 -R
total= 0
while (yes)
read sarray keep separator="\n" limit=100 "bigtextfile" name="btf"
print "Nof(btf):"+Nof(btf)
for i=1,Nof(btf)
total+= Tointeger( btf[i] )
endfor
if (l_out) break
endwhile
print "Total:"+total
quit
The output looks like:
Nof(btf):100
Nof(btf):100
Nof(btf):100
Nof(btf):100
Nof(btf):8
Nof(btf):0
Total:6744368
Note the use of the break
key word. The limit
flag is used to work
in batches of 100 until there are not 100 left and when the remaining
are processed.
In this case the while is really being used as a backwards goto
. ICM
has a goto
which can jump forward to a label formatted like
LABEL:
, but it can’t jump backwards. So the while is used.
FAQ: Is there some kind of iteration using {} expansion somehow?
Modular Code - Function Definition
The most basic way to organize functionality into different containers
is to use the call
command to import ICM commands contained in other
files. This is about like source
in Unix shell languages.
Here’s an example:
$ echo "a='Sample'" > example.icm
$ echo "print a" >> example.icm
$ echo "quit" >> example.icm
$ icm -s -e 'call "example.icm"'
Sample
Note that this hangs for some reason. The quit
command may not have
obvious behavior in these circumstances.
FAQ: What’s the difference between:
-
exit [s_message]
-
Quits to an interactive ICM shell.
-
break
-
Exits from loops and macros.
-
return
-
is for macros and functions.
-
quit
-
Quits script completely. Useful for CGI programs (i.e. not shell spawned).
Although ICM has a read
command which will load a particular file,
there is no shell-style source
command per se. Apparently, the
entire concept is inadvisable anyway because when ICM is updated, not
all external files will necessarily be compatible with the old
version.
FAQ: Is there an eval
kind of command?
Answer: There is. Basically the $
is an eval
.
icm/def> mystatement='show s_pdbDir'
icm/def> $mystatement
ftp://ftp.rcsb.org/pub/pdb/data/structures/divided/pdb/
Also consider the following example:
s = "print 'hello'"
set property command s
# or
set property command s auto # for autoexec status
I don’t really know what that does.
Commands
Commands are provided by ICM and can not be created or modified by normal users. They take options and arguments (not necessarily in that order). They can not be nested like functions.
FAQ: Is there an exit code equivalent?
Answer: Yes. Look at the result of Error()
after running a command.
Functions
ICM has numerous built in functions. Stylistically, these start with a capital letter and contain parameters (if any) in parentheses. In addition to taking parameters, functions can return values and can be used in assignments and nested expressions.
Functions can also be created by users using the following technique:
#!/pro/icm/icm/icmng -s
function UserDefinedFunction s_argument1
myarg='Passed by reference?'
return "The function returns:" + s_argument1
endfunction
myarg='Passed by value?'
print UserDefinedFunction(myarg)
print myarg
quit
This returns:
The function returns:Passed by value?
Passed by value?
Here is an example using an arbitrary number of arguments:
#!/pro/icm/icm/icmng -s
function Switcher s_argument1 s_argument2
return s_argument2 + s_argument1
endfunction
a= 'Chicken'
b= 'Egg'
print Switcher(a,b) # Outputs "EggChicken"
quit
Note that function (and macro) parameters must have a special naming
scheme. There must be a prefix of s_
for string types, r_
for real
types, i_
for integer types, etc. The complete list of how this
works is here. However, note
that advanced complex types that aren’t listed, for example
collections, should use the P_
prefix. The point to all this is that
if the parameters are all of different types, then the argument order
of the function call can be arbitrary.
FAQ: Is there a way to make a "module" or "package" that can keep name spaces clear? Answer: Use ‘call` to import user defined functions. Functions’ variables are local to them.
Note
|
When investigating ICM functions it is wise to read the manual entry on macros too since they are only subtly different and much of the explanation for functions was taken as given in the documentation for macros. |
Macros
Macros tend to have names capitalized like this: sortSeqByLength
. Of
course there are exceptions (homodel
, cool
, nice
, morph2tz
,
set_icmff
). The show
command can help figure out what’s going on
with macros.
It can do things like show the contents of a macro. You can also see
all the defined macros. For example, show macro
shows the whole list
of them with their parameters.
It is rumored that, like commands, macros can not be used in direct
nested expressions. Functions can like: a( b(x) )
If you need to get rid of some macro that you created, you can do it with:
delete macro anIllAdvisedMacro
Note
|
I don’t know if it’s a smart thing to do, but you can delete the ICM preconfigured macros from your session (they come back when you rerun ICM). This might be handy if ICM has taken some name you want to use or otherwise keep free. |
Also be aware of the set key
command which can bind keys to a
particular action. For example:
set key "F1" "set plane 1\n"
Of course this is already done and if you try to do it again, it will say `key [F1] is already bound.
Also show key
to see what keys are already defined.
Note
|
I actually couldn’t get key binding to work at all. Maybe it’s a GUI only thing. |
FAQ: How does one delete or modify key bindings?
Alias
You can do show alias
to reveal all of the currently defined
aliases. You can also do list alias
if you like to have options.
alias <name> <action>
delete alias <name>
Generally it is not recommended to use aliases in scripts.
FAQ: What’s the difference between an alias
and a macro
?
Input/Output
Environment
You can query the state of environment variables from ICM with the
Getenv
function. It works like this:
user= Getenv("USER")
if (user=="guest") then
print "You're a guest"
endif
If you’re unsure if an environment variable exists, you can look at something like:
Existenv("USER")
And if you need to set your own environment variables Putenv()
.
Option And Argument Parsing
ICM has its own way of doing options that is not exactly like normal Unix scripts. While not great for consistency with other shell scripting arrangements, it is however designed to have less redundant features and is often much less complicated to implement.
I do not think that ICM scripts have a built in way to handle short style options. Handling long options, however, is quite simple.
To use options with ICM scripts you can pass the options to a running
ICM session with the -a
option when running ICM (the ICM executable
does have some short style options, they’re just not available for
easy parsing in your scripts).
Note
|
The options you can pass to the ICM executable can be found here. |
Here’s the simplest demonstration of argument handling:
$ /pro/icm/icms/icmng64 -R -a x=3 y=simple
icm/def> Getarg("x")
3
icm/def> Getarg("y")
simple
Note: You can have arguments like -x=3
if you want, but you have to
use "-x" in the Getarg()
function. Probably best to just avoid that
potential confusion and leave the dashed options for the icm
executable.
This makes a more complex example clearer:
#!/pro/icm/icms/icmng64 -R
HELP= "Usage: $P [help] [a=<alpha>] [b=<beta>] [c] <arguments>"
if Getarg(help) quit HELP
# Pull out the options that the program expects.
alpha= Getarg("a","ADEFAULTVALUE",delete)
beta= Getarg("b","",delete)
gamma= Getarg("c","",delete)
scriptarguments= Getarg(list,delete)
if ( Nof(scriptarguments) < 1 ) quit " Error> At least one argument is required.\n" HELP
errorAction = "quit"
if(scriptarguments) then
print "a=", alpha
print "b=", beta
print "c=", gamma
print scriptarguments
quit
endif
Reading From Files
The most basic way to read data from a file in ICM is to create a string array with each line of the file being an item in the array. This looks something like:
read sarray comment name="mystory" "mystory.txt"
The keyword comment
causes lines that begin with the #
character
to be skipped.
When reading some kind of data, it is probably best to employ one of ICM’s fancier file reading methods. Here’s a comparison of the two methods. First the file is loaded as text into a string array. You can see that the file has a header row that isn’t part of the data per se.
icm/def> read sarray name="aa" "mydata.csv"
Info> 21 elements of sarray 'aa' loaded from mydata.csv
icm/def> aa[1:4]
#>S string_array
NAME,SHORT,CODE
Alanine,Ala,A
Arginine,Arg,R
Asparagine,Asn,N
Next the data is loaded into a table object. This allows its header to be correctly understood and used and the fields correctly parsed.
icm/def> read table separator="," header name="aa" "mydata.csv"
Info> table 'aa' ([3] columns) has been created
icm/def> aa[1:4]
#>T aa
#>-NAME--------SHORT-------CODE-------
Alanine Ala A
Arginine Arg R
Asparagine Asn N
"Aspartic acid" Asp D
If you’re reading something astronomically huge you may not wish to have it all load into an ICM object. You may not have enough memory.
FAQ: How does one read data from files? Need to include CSV into
tables (read table
), text into Sarrays (read sarray
), etc. Also
need to show how to do something with each line of text as it comes in
and not store it in a list. (see limit=n_records
)
FAQ: Maybe talk about stream strategy somewhere. Is a stream a type?
Reading From User
The Ask()
function can allow a script to pause and ask for user
input.
icm/def> n = Ask("Enter a number", 5)
Enter a number : 5
icm/def> n
5
In this case the default value is "5" and it is prompted. The behavior above is from just hitting enter at the prompt. Note that a colon is added so hopefully that is indeed the formatting you want.
FAQ: When using string types, you can use the keyword simple
after
the default value specification (no additional comma) - what does this
do?
Also there is the pause
command. Normally you supply an argument
specifying how many seconds to pause, however, if you don’t, it will
wait until the user hits a key.
Printing
Generally the contents of objects can be output by using the print
command.
There is also a show
command in ICM with 1000s of uses.
There is also a list
command with some print-like abilities.
ICM provides normal printf mechanisms for outputting explicitly
formatted text. There is printf
which outputs to stdout and the
special variable s_out
. There is sprintf
which only saves the
output in the special variable s_out
.
Writing To Files
There is fprint
which works as follows for outputting directly to
files:
fprintf append "overheat.log" "%s %.2f\n" "CPU1Temp", 42.4
FAQ: What will an .icb file be? Can a "session" be saved from a script? Any other odd cases? An entire ICM session can be saved from a script with the following approach:
$ icm -s
icm/def> a
Error> [1073] a: unknown word
icm/def> a = Pi
icm/def> a
3.14159
icm/def> write binary all "session.icb" delete
icm/def> quit
$ icm -s
icm/def> a
Error> [1073] a: unknown word
icm/def> read binary "session.icb"
icm/def> a
3.14159
FAQ: Tables to CSV? See the write
command which can do this.
Here’s an example of a table being written to a comma separated value file:
group table t {1 2 3} "a" {"one","two","three"} "b"
write t header separator="," "t.csv"
unix cat t.csv
a,b
1,one
2,two
3,three
write t separator="," "t.csv" # without header
unix cat t.csv
1,one
2,two
3,three
This can be recalled with the following:
read table separator="," header name="t" "t.csv"
ICM Web Technologies
Let’s say that you have an interest in creating a web service and you think that it might be a good idea to use ICM for some or all of that project. It’s fairly obvious why you wouldn’t use ICM as there are many good ways to make web services. Here are some of the compelling reasons that you might want to consider using ICM.
-
Your project involves chemistry, biology, genetics, proteins, etc.
-
Other parts of your project use ICM.
-
Your project involves chemical or genetic databases.
-
Your project involves protein docking.
-
You would like to have molecules depicted graphically.
-
You really like ICM.
Running ICM As A CGI Program
If you want the web server to not just deliver the source code of an
ICM program, but rather execute it and deliver the results, you must
configure that in the web server configuration. There are known places
where this is done globally, but when you want to do it in some
arbitrary directory, you can use a .htaccess
file which allows you
to make custom local configuration changes. To have files that end in
".cgi", ".py", or ".icm" execute, create a .htaccess
file in the
directory where these programs will be served which looks like this:
AddHandler cgi-script .cgi .icm .py
Options +ExecCGI
SetEnv LM_LICENSE_FILE @lic.your-domain.com
Note
|
To minimize problems, it is good when developing ICM scripts to
make sure that they always run with a LM_LICENSE_FILE variable set.
This applies to CGI programs. Including it here ensures that it is
done. Make sure to use the correct server or location for your ICM
license. |
CGI Execution Of ICM
The first line of your CGI script should contain a line that looks something like one of these:
#!/yourpathtoICM/icm -w/yourpathtoICM
#!/yourpathtoICM/icm -s
#!/yourpathtoICM/icmng -s
There are different reasons to use the different flags and executables. I’m including them here to show what has worked in various situations. Experiment.
It looks like -w
, for example will "webify" things a bit. One of the
features of this mode is that error messages are somewhat decorated by
HTML. This is true even when run from the console. For example, I got
this HTML fragment as an error:
<hr><h3>Error: [1073] enfor: unknown word</h3><hr>
Don’t forget to make your script "executable" with something like
chmod a+x myscript.icm
. A good strategy is to develop programs that
can run on the command line or with a web interface.
Libraries
It cat be frustrating to have your procedure work fine in an interactive command line session and then fail spectacularly when put into a program. Specifically it wills seem like valid commands are missing. This can happen if macro libraries, which are loaded automatically during interactive sessions, fail to load.
The cure is to simply include something like this into your scripts:
call "/pro/icm/icm/_macro"
read library
Generating HTML
Some people don’t mind mixing up HTML and proper programming but I find that it makes syntax highlighting terrible and it opens a lot of possibilities for errors trying to match opening and closing tags. Matching tags is the kind of thing a computer should be doing and when writing real programs, you can let the program do this. Here is my function to do this translated to ICM from my Python version.
#!/pro/icm/icm/icmng -s
#html_tagger.icm - Chris X Edwards
#No HTML in my programs! This function functionalizes HTML tags.
#Example: tag('a','click here', "{'href':'http://www.xed.ch'}")
#Produces: <a href="http://www.xed.ch">click here</a>
# Param1= name of tag (table, img, body, etc)
# Param2= contents of tag <tag>This text</tag>
# Param3= dictionary of attributes {'alt':'[bullet]','height':'100'}
function Tag s_tag s_content s_attlist
s_tagstring= "<"+s_tag
if (Type(s_content) == 'unknown') then
s_content=''
endif
if (Type(s_attlist) != 'unknown') then
attC= Collection(s_attlist)
S_keys= Name( attC )
for i=1,Nof(S_keys)
s_att += ' '+S_keys[i]+'="'+attC[ S_keys[i] ]+'"'
endfor
s_tagstring += s_att
endif
if (Length(s_content) > 0) then
s_tagstring += ">\n" + s_content + "\n</" + s_tag + ">\n"
else
s_tagstring += "/>\n"
endif
return s_tagstring
endfunction
s_title= Tag('head', Tag('title', "A Test"))
s_photo= Tag('img','',"{'src':'./photo.jpg','width':'100','height':'200'}")
s_par= Tag('p', "No html here. Just sensible code.")
s_hr= Tag('hr')
s_text= Tag('body', s_photo + s_par + s_hr,"{'bgcolor':'#cecece'}" )
print Tag('html', s_title + s_text)
quit
Running this will produce:
<html> <head> <title> A Test </title> </head> <body bgcolor="#cecece"> <img height="200" src="./photo.jpg" width="100"/> <p> No html here. Just sensible code. </p> <hr/> </body> </html>
Note
|
The quoting on the attribute dictionary is a bit strange in ICM but basically you need to use a JSON-like string that is itself entirely quoted. |
HTML Documents In ICM
As described in this web page, ICM has the ability to have HTML documents in working memory and to display them in a type of browser (GUI, I presume). This is started with something like:
read html "a.html" # reads and sets the property mask
# Create a new HTML document.
s = "<html><h1>TITLE</h1></html>"
set property html s
CGI Input
CGI Variable Handling
ICM has very convenient facilities to handle CGI input. The trick is
that the Collection()
function does a lot of fancy things with CGI
query strings. It even handles POST methods for loading files that are
uploaded from a browser. Here is a succinct example:
<html> <form action="m.cgi" enctype="multipart/form-data" method="post"> <p> Type some text (if you like):<br> <input type="text" name="textline" size="30"> </p> <p> Please specify a file, or a set of files:<br> <input type="file" name="datafile" size="40"> </p> <div> <input type="submit" value="Send"> </div> </form> </html>
#!/yourpathtoICM/icm -w/yourpathtoICM
printf "Content-type: text/html;\n\n"
cc = Collection(web)
cc["param1"] # get parameter
cc["datafile","body"] # blob with file content
read binary input=cc["datafile","body"] # read from blob
quit
Here is a function that processes a POST method for receiving and using binary files. This allows the uploaded file to never need to reside on the web server. This is only a part of such a program, but it clearly shows the important bits for handling POST binary file uploads.
function Processpost
# Note "web" is an option keyword here, not a mysterious variable.
c= Collection(web)
webvars= Name(c)
if ( Index(Name(c),'datafile') ) then
filebytes= Length(c['datafile','data'])
if ( filebytes == 0 ) then
return Makehtml( br+Tag('b', 'You did not specify a file!') )
endif
endif
read binary input=c['datafile','data']
fullreport= c['full'] # From radio button
myresis= Name(a_./*)
if ( c['full'] == '1' ) then
msg= 'Full Report:' + br
msg+= Sum(myresis,' + ')
else
msg= 'Summary Report:' + br
msg+= Tostring(Nof(myresis)) + ' residues (and other junk).'
endif
return Makehtml( msg )
endfunction
Integrated Form And Handling
It is common to create an HTML document that contains a form and a CGI
program that handles the data filled into the form. There is no reason
not to use the flexibility of the form handling program to also
generate the form. The huge advantage of this is that the form and the
handling of the form elements will be in the same place. If, for
example, you need to add or remove a field, you only need to edit one
file. If you write the program sensibly, you might be able to only
edit one thing for such a change. Here is an example of a CGI program
that handles CGI data, or, if none is given, prompts for it with a
form. This program requires the html_tagger
function mentioned above.
#!/yourpathtoICM/icm -s
# cgiform.cgi - A template for a complete CGI system in ICM.
# This version provides the framework for generating a form and, if
# parameters are supplied, processing the results of the form.
call 'html_tagger.icm'
CONTYPE= 'Content-type: text/html\n\n'
# Find name of this script from the web form's perspective.
fullscriptpath= File(last)
scriptparts= Split(fullscriptpath,'/')
thelast= Nof(scriptparts)
SCRIPT= './'+ scriptparts[thelast]
function Makeform
formlabel= Tag('h4','This Is A Sample Form:')
ff= Tag('p',Tag('input','Peptide?',"{'type':'checkbox','name':'pep','value':'1'}") )
ff+= Tag('p',Tag('input','Protein?',"{'type':'checkbox','name':'pro','value':'1'}") )
ff+= Tag('p',Tag('input','Cis',"{'type':'radio','name':'rb1','value':'C','checked':'1'}") )
ff+= Tag('p',Tag('input','Trans',"{'type':'radio','name':'rb1','value':'T'}") )
ff+= Tag('p',Tag('input','',"{'type':'submit'}") )
f= Tag('form',ff, "{'action':'"+SCRIPT+"', 'method':'GET', 'enctype':'multipart/form-data'}")
return formlabel + f
endfunction
function Processform
c= Collection(web)
s_formdata= String()
S_keys= Name( c )
for i=1,Nof(S_keys)
s_formdata+= Tag('li',S_keys[i]+' : '+c[ S_keys[i] ])
endfor
return Tag('ul',s_formdata)
endfunction
function Makehtml s_contents
s_title= Tag('head', Tag('title', 'A CGI Test'))
s_body= Tag('body', s_contents,"{'bgcolor':'#cecece'}" )
return Tag('html', s_title + s_body)
endfunction
# =============== Main =================
if ( Existenv('REQUEST_METHOD') ) then
REQUEST_METHOD= Getenv('REQUEST_METHOD') # GET or POST - `web` #parser needs this
endif
message= Makeform()
if (REQUEST_METHOD == 'GET') then
if ( Existenv('QUERY_STRING') & Length(Getenv('QUERY_STRING')) > 0 ) then
message+= Processform() + 'Processed form!'
endif
else
message+= 'POST HTTP method not supported yet!'
endif
print CONTYPE + Makehtml(message)
quit
Outputting Non-Text Data
Sometimes you don’t want to send an HTML document to the requesting client. Sometimes you want to send a different kind of data. For example, you may be generating a plot or graphic on the fly based on CGI input and you need to return an image data stream. This can be tricky in ICM but the following technique handles it with no problems:
function ImgTest
CONTYPE= "Content-type: image/png\n\n"
write blob Blob(CONTYPE) "/dev/stdout"
myPath= '/var/www/fs/users/myname/myapp/'
s_iName="test.png"
fullFileName= myPath + s_iName
read blob name="tempimg" fullFileName
write blob tempimg "/dev/stdout"
# Make sure you make this function = something to prevent return's output.
return ''
endfunction
This technique can be useful in a program that normally receives CGI input and returns an HTML page. But the program can also be set up to handle specially marked requests (http://url?getanimage=true) to return graphics and other content. Then the main HTML output can contain embedded links to the program effectively calling it again to furnish the rest of the content.
Sanitizing Input
If you are writing web applications, it is common for them to accept inputs to provide the custom functionality the user requires. Unfortunately bad people live on the internets and they do bad things. To prevent unintended use of your scripts, it is a good idea to "sanitize" the data you collect from the wild internet. This means that if you do not expect certain characters to be in your input, you should disallow them. Here is my basic sanitizing function.
function InputOK s_suspect
good= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-.'
cleaned= Trim(s_suspect, good)
if (Length(s_suspect) == Length(cleaned)) then
return 1
else
return 0
endif
endfunction
teststring= "This: #is not@ ok!"
if (InputOK(teststring)) then
print "Ok."
else
print "Error: Invalid characters in input."
endif
ICM Tables To HTML
One nice trick that ICM can do to assist web development is to convert ICM tables into very nice HTML tables. The basic way to do that is the following.
# Create a simple table.
add column t {1 2 3} Chemical({"CCC","CCO","CCN"})
# Use the sort keyword to make the columns sortable.
# Chemicals will be exported as HTML5 canvases.
show html t sort
The sort
keyword adds some magical stuff to the output so that the
table is "sortable". More specifically, it comes with some Javascript
code (or references to it) that will resort the table on the client’s
browser. This code is based on
Stuart Langridge’s
"sortable" code. The Molsoft team have a version that
lives here.
One problem with this code is that it generates a complete HTML document instead of an HTML fragment. This means that it would, for example, be less convenient to include two sortable tables from ICM tables in a single HTML document.
One way to solve this problem is to parse the output of this show
html
functionality. This is possible with the following function:
function HtmlTableSplit( s_tab l_sort )
l_commands = l_info = no
show html $s_tab output = "sss" !l_sort? : sort
c = Collection( )
c["head"] = Match( sss, "(?n)<head>(.*)</head>" 1 )
c["table"] = Match( sss, "(?n)<body[^>]*>(.*)</body>" 1 )
c["onload"] = Match( sss, "<body.*?onload=(.*?)>" 1 )
return c
endfunction
# .. use:
c = HtmlTableSplit( "t", yes )
# Then you need to add c["head"] to the head section, the onload call
# inside the <body ... > definition and the table itself inside the body.
Another way around this limitation is to make your own tables explicitly. This may not be as convenient but sometimes if you want something done right, you have to do it yourself. Here are some functions that can produce simple HTML tables from an ICM table. Note that these assume the HTML tagger function discussed previously.
# Create an HTML header row from an ICM table.
function UIcmtab2htmltab_header T_the_table
Ufields=Field(Name(T_the_table) 2 '.' )
Uhttabhead= ''
for Ui=1,Nof(Ufields)
Uhttabhead //= Tag('th',Ufields[Ui])
endfor
Uhttabhead= Tag('tr',Uhttabhead)
return Uhttabhead
endfunction
# Pull out table's cell data and make into correct HTML tr and td.
function UIcmtab2htmltab_cells T_the_table
Uhttab= ''
Ufields=Field(Name(T_the_table) 2 '.' )
for Ui=1,Nof(T_the_table)
Uhtrow= ''
Urow = Collection( T_the_table[Ui] )
for Uj=1,Nof( Ufields )
Ucell= String( Urow[ Ufields [Uj] ])
Uhtrow //= Tag('td',Ucell)
endfor
Uhttab //= Tag('tr',Uhtrow)
endfor
return Uhttab
endfunction
HTML5 Canvas
Pretty much all sane browsers today support
the very useful HTML5 canvas
tag which allows for composing
arbitrary graphics using JavaScript. This has obvious implications for
domain specific technical diagrams like molecular diagrams.
The Molsoft function man
page has this tantalizing and extremely brief mention of the topic
under the String()
function
String ( X_chem, html ) - return HTML5 canvas and rendering JavaScript
I don’t know exactly what that means. What is an X_chem
? Is it
different from X_chemarray
?
Here is a function which will create the HTML5 canvas tag. Note that if you have multiple ones of these they will all be in the same place. The way I fixed that was to do something like this:
Ucell= Replace(Ucell,"chem_1","chem_"+String(Ui))
Do this in the loop where Ui
is the number of the molecule you’re
on. Basically make them all different if you want it to render to
different canvases.
Note that you need to specify the size of the canvas too, it’s not optional.
# Create an HTML5 <canvas> tag graphical representation of a SMILES string.
function USmiles2canvas s_smiles
Ucanw= 200
Ucanh= 200
Ucan= String( Chemical(s_smiles) Ucanw Ucanh html)
return Ucan
endfunction
I also found that the executable I used did matter. Some versions of
ICM may not have this feature compiled in. Check the error message for
String(x y)
. Look for:
String( <X_chem> i_w i_h html ) => <s_html5_canvas>
If that is part of the error message for String, then you can be pretty sure it should work.
SVG
It is also possible to export chemical as svg.
write image Chemical("CCCO") "xxx.svg"
Note that this requires that you be running ICM in graphical mode
(-g
).
ActiveICM
A discussion of web technologies featuring ICM would not be complete without discussing ActiveICM. This is a browser plugin which can allow full 3-d molecular models to be rendered and manipulated in a browser window. The down side to this is that the plug in can be tricky to get working. Even though it costs no money, the downloading and configuration can limit spontaneity. However, if the investment is made, one is empowered by a truly excellent way to view molecules from a web browser. ActiveICM is vastly better than the popular Java alternatives and as a bonus you don’t need to have Java, the security nightmare, installed.
ActiveICM Client Browser Plugin
To get ActiveICM working on my Ubuntu installation, I had to add some things.
sudo apt-get install libxt-dev libxt6
sudo apt-get install libxext-dev libxext6
sudo apt-get install libgtkgl2.0-1 libgtkgl2.0-dev
sudo apt-get install libgtkglext1-dev libgtkglext1
You’ll need the plugin which can be downloaded from the Molsoft website.
For Linux it comes as a gzipped tar file. Do something like this to unpack:
tar -xvzf activeicm-1.1-7.x64.tgz
Change to the activeicmplugin
directory that is created and run the
installer with:
sh activeicm-plugin-installer
For me on Ubuntu 12.04.2 LTS, I got the following error:
ERROR: Your glibc library is older than 2.3.
Please update your glibc library.
Fortunately I found
this similar problem
and the solution seemed to work. So basically comment out the if
statement around the "valid-glibc" check so that it always echoes
"valid-glibc". Once the installer runs cleanly, it should work. For me
it works on chromium-browser
and firefox
.
To test, try the following sites:
Creating ActiveICM Content
<html> <body> <OBJECT ID="ActiveIcmCtl" WIDTH="100%" HEIGHT="100%" type="application/x-molsoft-icb"> <param name="projectFile" value="YOURICMSTUFFHERE.icb"> <!-- Good Idea to provide the link to get ActiveICM or help if it's not working. --> Click <a href="http://www.molsoft.com/getbrowser.cgi?product=activeicm&act=list" target="_blank"> here </a> to download ActiveICM plug-in </OBJECT> </body></html>
To make something that can be viewed you need to provide an ICM binary
file (YOURICMSTUFFHERE.icb
shown above). To make one of these, I
think you pretty much just have to do something like:
build smiles name="mefloquine" "OC(C1CCCCN1)C1=CC(=NC2=C1C=CC=C2C(F)(F)F)C(F)(F)F"
write binary mefloquine "./mefloquine.icb"
However, this didn’t quite work for me. I think maybe the object never got "displayed" and it could be displayed without a graphical session or a virtual X server session. This is not an esoteric issue since if you are writing web software to create custom molecular objects to view, they will probably be run on a system with no graphics.
Examples Of ICM Web Applications
The team at Molsoft has written some nice applications in JavaScript that shows this off. These might be useful references:
Reserved Words
The online reference for ICM functions is here.
There are a lot of reserved words that you should avoid. Sometimes
there is an alias (ux
), a command (unix
), and a function
(Unix()
). With such a prodigious collection of reserved words, it
might be a good idea to prefix your variables with something
distinctive.
Aliases
There are many aliases that are predefined so it’s a good idea not to
use the same identifier for your stuff. For example, q
is an alias
for the quit
command. To see all the aliases use list alias
.
ali |
alignment |
at |
atom |
cd |
set directory "$1" |
cn |
drestraint |
cp |
copy |
csv |
table separator="," |
ds |
display |
dsb |
(complicated) |
dsbb |
(complicated) |
dssp |
assign sstructure |
echo |
|
ey |
energy |
hi |
history 20 |
gd |
gradient |
la |
label |
lb |
library |
ls |
list |
lsdock |
list macro "dock" |
lsar |
list iarray rarray sarray |
mc |
montecarlo |
ml |
molecule |
mt |
matrix |
mv |
move |
prf |
profile |
protect |
set property delete off |
unprotect |
set property delete on |
re |
residue |
rex |
read object "/data/icm/xpdb/$1" |
getpdblist |
(complicated) |
GT |
(complicated) |
rm |
delete |
rs |
vrestraint |
sar |
sarray |
seq |
sequence |
shdb |
show database |
ssbond |
disulfide bond |
ty |
types |
tz |
tether |
unds |
undisplay |
ux |
unix |
va |
variable |
gapOpen |
gapFunction[1] |
gapExtension |
gapFunction[2] |
shininess |
GRAPHICS.light[1] |
QUOTE |
"\"" |
MAX |
Max(Max( $1 )) |
MIN |
Min(Min( $1 )) |
SUM |
Sum(Sum( $1 )) |
BS |
build string "$0" |
COLRELIA |
color ribbon $1 Smooth( $1 , -Score( $1 ) , 6. ) |
DIFF |
a_/A & Replace(Replace( $1 ,"[- ]","%"),"[!.#~+^]"," ") |
FRAG |
(complicated) |
NORM |
($1 - Mean($1))/Rmsd($1) |
PSEQID |
(complicated) |
SEQID |
(complicated) |
SEQIDo |
(Max(25.,290.15/Power($1,0.562))+5.) |
remark |
set comment a_ Sum(Namex(a_)) + "$0" |
rinx |
read index s_inxDir + "$1" |
rsbase |
read sequence SBASE.ID=="$1" |
rswiss |
read sequence SWISS.ID=="$1" |
loadVtConf |
(complicated) |
ssbase |
show SBASE.ID=="$1" |
sswiss |
show SWISS.ID=="$1" |
pf |
ds skin Sphere(a_3//* 7) & a_1,2 a_1,2 |
WIN |
(View()[35:36]) |
ICM_LITE |
(Index(Version(),"mini")!=0) |
testall |
call s_icmhome+"test/all" |
HDR_PROP_OFF |
dummy="" |
sys |
unix |
FR_FIRST |
-1 |
FR_PREV |
-2 |
FR_NEXT |
-3 |
FR_LAST |
-4 |
ST_UNDEF |
0 |
ST_TWEEN |
1 |
ST_ROTATE |
2 |
ST_ROCK |
3 |
ST_STILL |
4 |
sys |
unix |
GROUPTAB |
group table append $s_projName header |
dockIdentSites |
icmPocketFinder $1 6. yes yes |
COLRELIA |
color ribbon $1 Smooth( $1 , -Score( $1 ) , 10.) |
searchSWS |
readUniprot |
Commands
The following key words are built in commands in ICM:
Interaction and Output
Programming
Bioscience
align alignment append assign build cartesian clash compare convert enumerate fast fasta find fix group index link loop make minimize mmff modify molcart molecule montecarlo move nucleotide occupancy peptide predict prosite protein reverse site smiles smooth ssearch strip superimpose swiss tautomer transform translate tree unfix unique volume
Reserved Words Which Are Options To Commands
accessibility all amber angle antialias area aselection atom auto auxiliary axis background ball bar base bfactor binary bold bond born boundary box bw catalog cavity cell chain charge chemical chiral cistrans cmyk column command comment comp_matrix conf cpk csd dash database directory distance disulfide dot drestraint energy error evolution exact exclude factor field filename filter flat font foreground formal format frame full gamess gcg genome gif gradient graphic grid grob hbond header heavy html hydrogen iarray icmdb idb identity image input integer intensity italic iupac join jpeg json kernel last lection left library limit local logical map margin material matrix memory merit mmcif model mol mol2 moldb molsar movie msf mute name new none nosort number object off on only oracle origin output page parray pattern pca pdb pharmacophore pipe pir plane pmf png postscript potential pov preference preview problem profile project property pseudo query rainbow rarray reaction real reflection refresh regression residue resolution restore rgb ribbon right ring salt sarray segment selftether separator sequence session similarity simple size skin slide sln solid solution sql sstructure stack static stdin stdout stereo stick string surface svariable symmetry system table targa term tether texture topology torsion transparent type underline unix unknown user variable version view virtual vrestraint vselection water wavefront weight window wire xplor xstick
More Like A System Variable Than A Command?
Functions
Math Functions
The following functions are related to mathematical computation.
Geometry and Trigonometry
Vector and Matrix
Statistics and Randomness
Corr, Histogram, Laplacian, LinearFit, LinearModel, Mean, Probability, Random, Score@, Shuffle, Smooth, SolveQuadratic, SolveQubic, Sum@,
Programming Functions
The following functions are useful for performing software related tasks.
Types and Casting
Bioscience Functions
Acc, Align, Angle, Area, Ask, Askg, Atom, Augment, Axis, Bfactor, Boltzmann, Box, Bracket, Cad, Cell, Charge, Chemical, Cluster, Color, Consensus, Deletion, Descriptor, Energy, Extension, Formula, Gradient, Group, Header, Index, Info(image), Insertion, Label, Length, Map, Mass, MaxHKL, Mol, Moment, Name@, Namex, Next, Obj, Occupancy, Parray, Pattern, Potential, Predict, Probability, Profile, Radius, Reference, Res, Resali, Resolution, Rfactor, Rfree, Ring, Score, Select, Sequence, Site, Smiles, Sphere, Sql, Srmsd@, Srmsd@, Sstructure, Sum@, Symgroup, Temperature, Torsion, Tr123, Tr321, Trans, Transform, Trim(sequence), Turn, Type@, Value, Version, Volume@, Xyz,
Macros
alignSS, aquaSitesBG, calcEnergyStrain, calcEnsembleAver, calcMaps, calcPairSeqIdsFromAli, calcPepHelicity, calcProtUnfoldingEnergy, calcRmsd, calcSeqContent, calc_nosauc, chemSuper3D, convert2Dto3D, convert3Dto3D, convertObject, cool, ds3D, dsCellBox, dsChem, dsCustom, dsPocket, dsPropertySkin, dsPrositePdb, dsRebel, dsSeqPdbOutput, dsSkinLabel, dsStackConf, dsVarLabels, dsXyz, evalSidechainFlex, findFuncMin, findFuncZero, findSymNeighbors, find_related_sequences, gAlignTwoSequences, gCalcArea, gCalcBindingEnergy , gCalcDihedralAngle, homodel, icmCavityFinder, icmMacroShape, icmPmfProfile, icmPocketFinder, loadEDS, loadEDSweb, makeAxisArrow, makeIndexChemDb, makeIndexSwiss, makePdbFromStereo, makePharma, makeSimpleDockObj, makeSimpleModel, mergePdb, mkUniqPdbSequences, modifyGroupSmiles, morph2tz, nice, optimizeHbonds, parrayTo3D, parrayToMol, plot2DSeq, plotBestEnergies, plotCluster, plotFlexibility, plotMatrix, plotRama, plotRose, plotSeqDotMatrix2, plotSeqDotMatrix, plotSeqProperty, predictSeq, prepSwiss, printMatrix, printPostScript, printTorsions, rdBlastOutput, rdSeqTab, refineModel, regul, remarkObj, searchObjSegment, searchPatternDb, searchPatternPdb, searchSeqDb, searchSeqFullPdb, searchSeqPdb, searchSeqProsite, searchSeqSwiss, setResLabel, seticmff, sortSeqByLength, waterDisplacement,
Chemistry
I am not a chemist or even someone who really should ever be using ICM but sometimes I need to do simple things with it involving its actual real purpose, chemistry. Here is a tiny example collection of simple chemistry related things that ICM can do.
SMILES to SDF
Need an SDF file to work with but you don’t have one? Often if you know what the molecule is you can hunt down it’s SMILES string on Wikipedia and do this.
icm/C4H10O3> ethylene_oxide="C1CO1"
icm/C4H10O3> String(Chemical(ethylene_oxide))
C2H4O
MOLSOFT 01031707042D
3 3 0 0 0 0 0 0 0 0999 V2000
0.0000 0.0000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1.2124 0.7000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
1.2124 -0.7000 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0 0 0 0
3 1 1 0 0 0 0
2 3 1 0 0 0 0
M END
$$$$
Create 3D Molecular Model
To take a SMILES string and make a 3D model use the build command.
build smiles ethylene_oxide
You can give it a name with name="eto"
(mind the quotes on the
name). If you don’t name it, it will get a chemical name (like "H2O").
If you need to build a protein or a peptide chain, that is extremely easy to do. Going with the easiest, you can just load a model from PDB.
read pdb "3hag"
I’m not sure if this converts from bad PDB representation to proper ICM version. You can also just build the molecule yourself from a peptide sequence. Here’s Lixisenatide, a drug for treating diabetes made from something resembling Gila monster venom.
build string name="gomesin3" "XC1RRLC2YKQRC2VTYC1RGR"
randomize v_//!V,omg 180.0 # create random starting conformation
Selections
Selections can be tricky. You can select atoms, residues, basically anything conceivable. Here’s the full documentation on selections. Generally selections look like this.
prefix _ [ object(s) . ] molecule(s) / residue(s) / atom(s) or variable(s)
Here I load a PDB structure and then delete all the atoms that aren’t part of a particular alpha helix I’m interested in.
read pdb "1ove"
delete a_1ove./!252:262
Double clicking a workspace object will select atoms in an object. And double clicking empty space in the hierarchical workspace list will unselect everything.
Select something with a box using right button and then erase everything but that with this.
delete !as_graph
Select all? It’s something like this, but probably not exactly.
select a_*//*
Analysis
How to extract the DrugLikeness
property from the Predict function.
Shown here starting with a SMILES string.
Predict(Chemical('Oc1ccc(O)cc1C(C)(C)C')).DrugLikeness
-0.887574
Predict(Chemical('Cc1c(OC)c(C)cnc1CS(=O)c2nc3ccc(OC)cc3n2')).DrugLikeness
0.88296
Negative are not drug like, positive are.
Superimpose
Often objects wander around in space and you’d really like them to be pointed the same way in the same place. Here’s what the Expert technique is.
superimpose a_1.1 a_2.1 align minimize
Display
These commands do a good job of putting the stuff on the screen.
center
center static
Here is a way to get rid of the cartoons ribbon display that usually is popular.
GRAPHICS.ribbonWorm=yes
ribbonStyle=5
Thanks
Thanks to Andrey I. for contributions and review of this guide. None of the mistakes in this have anything to do with him! Same for The Expert.
Questions
-
How do I load a table from an icb file, ex.
/pro/bin/molScreenOutputMerge.icm
output. See~/X/P/molscreen/folic_acid.icb
-
How do I show all objects that are loaded? Don’t know, but have a look at variable
t
when loading an icb file.