|
Each
term of the potential energy function is
represented by one or two Energy objects. The 19
Energy objects share many common features and so
they are used in very similar ways. The differences
arise from whether an object is an Inclusion or an
Exclusion type and whether the energy term involves
closely bonded atoms or non-bonded
atoms.
Preliminaries
The
AtomMap
type is used to express the atom hierarchy in YUP.
There are three kinds of
AtomMaps:
Atoms, Groups and Root. At the top of the atom
hierarchy is the Root AtomMap.
A file directory is bound to every Root
AtomMap
that is created. This is a directory that contains
force field parameter files. The Root
AtomMap
is used to tie the various parts of the molecular
model together. Energy objects are created with a
reference to the Root AtomMap;
they look for the appropriate parameter file in the
directory that is bound with the Root
AtomMap.
Another type of object, the AtomVector
is used to represent the Coordinates and Gradients;
these objects are created with a reference to the
Root AtomMap.
In turn, the AtomVectors
are bound to each Energy object.
The
force field is assembled using the currency of Atom
AtomMaps,
i.e., atoms are referenced not by name nor by atom
number, but by their AtomMap.
Each Energy object registers a list of
participating atoms by their
AtomMaps;
the AtomMap-based
lists are easier to modify. However, it is more
efficient to reference the atoms by an index or
atom number during the evaluation of the energy and
gradients. Therefore the
AtomMap
lists have to be compiled into atom number
lists.
In
these and following pages, methods and functions
are summarized in tables. These tables list
arguments in the order that they are expected. Some
methods and functions allow argument lists that
contain keyword-value pairs. If you use this method
of specifying an argument value, you need not
follow the prescribed order of course.
Atom
groups, such as the three atoms that make up an
angle term, are represented as tuples of
AtomMaps.
Tuples are Python data structures - specifically
they are inmutable lists. Tuples are written
between parentheses. For example, an angle tuple
looks like this: (
a, b, c )
where a,
b
and c
are Atom AtomMaps
of the three atoms that make up the angle. Each
tuple is logically a single compound object and the
parentheses are part of the tuple. Thus, when
written as part of an argument list it would look
like this: Object.SomeMethod(
(
a, b, c )
). Note the apparent double set of
parentheses.
Atom
types are referenced by name, i.e., a character
string. There are two ways of referencing
interaction types: the type string or a tuple of
atom types. For example if
"a",
"b",
"c"
are atom type names, then an example of an angle
type is expressed as ":a:b:c:"
or (
"c", "b", "a" ).
Note that ":a:c:b:"
and (
"b", "a", "c" )
are different angle types.
An
atom may be assigned a null atom type; this is the
empty string "". This has the effect of pulling the
atom out of all interactions. (The interactions
remain in the Energy AtomMap-based
lists but they do not appear in the
atomnumber-based lists.). An interaction type that
contains at least one null atom type is itself a
null interaction. For example
":a::c:"
or (
"", "c", "" )
are null angle types. Null interaction types are
not evaluated.
Creating
an Energy Object
The
first step in using an Energy object is to create
it. This is done by calling the constructor
function which is always given the same name as the
Energy module. The constructor always require, at a
minimum, the Root AtomMap
and the label. The label is a character string.
Each Energy object should be given a unique label
because the label is used to pick an Energy object
out of a list (for example). The label is also
printed as a column heading in tables of energy.
The label may be truncated to fit the column width
so the leading characters of labels should also be
unique.
The
constructor functions may take other arguments.
These are usually optional and have preset values.
The presets are conservative sensible
values. The
values of most arguments can be set to new values
throughout a simulation.
If
needed, the constructor function will read an
appropriate parameter file from the parameter
directory that is registered with the Root
AtomMap.
If it expects a parameter file and the file is not
present, the Energy object will not be
constructed.
The
constructor returns a new empty Energy object. This
has different meanings for Energy objects of the
Inclusion and Exclusion types. An empty Inclusion
type Energy object means just that - there are no
participants and the energy and gradients will
always evaluate to zero values. An Inclusion type
Energy object expects groups of participating atoms
to be registered with it. An empty Exclusion type
Energy object means that all pair interactions will
be evaluated. An Exclusion type Energy object
expects pairs of exceptions to be registered with
it.
The
memory quantum is the amount by which memory for a
growing list is incrementally allocated. Setting a
small quantum will result in more reallocation
attempts; this may result in memory fragmentation
which may in turn result in allocation failures. If
the quantum is set too high, there may be
insufficient memory to satisfy some allocation
attempts. Since it is impossible to specify an
exact quantum, the next best thing is to specify a
quantum that is somewhat more than is required.
Memory for the list is allocated once and
reallocated one other time (during the compile
stage, to reclaim unused space).
The
constructor function returns a handle to the new
Energy object. This should be assigned to a Python
variable so that the object can be manipulated.
Normally, the new object is also entered in a list
of Energy object. The Potential
object manages this list.
Managing
Energy Objects
Once
an Energy is created, it can be filled with groups
of either participating or excluded atoms. The
groups may be modified or removed and new groups
may be registered.
A
newly created Inclusion type Energy object is
empty. Groups of participating atoms are registered
using the add()
method (also known as include()
and insert()).
This method requires a tuple of Atom
AtomMaps.
For example the add()
method of the Bonds
object requires a tuple of two Atom
AtomMaps.
The second item in the argument list is optional.
If not specified, this atom group will be assigned
an interaction type that is formed from the
inclusion atom types of each atom. This assignment
does not take place until the object is compiled.
The second argument, if specified, must be a tuple
of inclusion atom type names. This interaction will
be assigned the specific interaction type
immediately. Such an assignment is permanent. If
the atom types are changed the same interaction
type is used regardless. This can be reversed by
calling the modify()
method. The modify()
method is used to change the interaction type
assigned to a registered atom group. This is either
to bind a specific interaction type to an existing
atom group, or to remove any specific interaction
type that may have been assigned to that group. In
the latter case, the interaction type will then be
based on the atom types of the individual atoms and
this will be assigned when the object is compiled.
Finally, participating groups can be removed from
the Energy object using the
delete()
method (also known as subtract()
and exclude()).
The delete()
method removes only the first occurrence of the
named group.
A
newly created Exclusion type Energy object is empty
but only because it is devoid of exclusions. Pairs
of atoms can be excluded from the interaction by
using the exclude()
method (also known as delete()
and subtract()).
There is only one item in the argument list, a
tuple of two Atom AtomMaps.
An exclusion pair may be registered more than once;
the duplicates are removed during compilation.
Exclusion type Energy objects do not support the
modify()
method. Interaction types are assigned based on the
exclusion atom types of the pair of atoms. An atom
pair cannot be assigned a specific interaction
type. Finally, a previously excluded interaction
can be restored by using the
include()
method (also known as add()
and insert()).
This will remove only the first occurrence of the
specified tuple from the exclusion list. If
duplicates remain, a single attempt to restore the
interaction will not have its intended
effect.
The
methods discussed in this section work on
AtomMap-based
lists. An energy object must be compiled before
energy evaluation. The compilation converts
AtomMap-based
lists to atomnumber-based list. The latter lists
are used in the evaluation of the energy and
gradients. Whenever any of the methods discussed in
this section is used, the atomnumber-based lists
are emptied.
Compiling
Energy Objects
The
compile()
method is used to compile an Energy object. The
method accepts two optional items in its argument
list. However, the two items must be specified in
the first call of this method. These are two
AtomVectors,
the first is the Coordinates vector and the second
is the Gradients vector. References to these
vectors will be saved with the object. In
subsequent calls to compile(),
AtomVectors
are specified only if it is desired to bind new
vectors to the Energy object.
The
main task of the compile()
method is to translate the
AtomMap-based
lists maintained by the management methods
(previous section) to the lists that are based on
atom or index numbers used in the evaluation of the
energy and gradients (next section).
For
Inclusion type Energy objects, interaction types
are also assigned to those groups that have not yet
been assigned. If any participating atom has a null
atom type, the group is not added to the atom
number-based lists. If an interaction type is not
present in the parameter table, an exception is
raised. You cannot proceed until you have resolved
this. There are several solutions: assigning atom
types to the atoms that will combine to an
interaction type that is present in the parameter
table; assign to the group a specific interaction
type that is present in the parameter table; quit
and add the required parameters to the parameter
file.
For
Exclusion type Energy objects, the compilation
process is easier; duplicate pairs are removed and
a sorted exclusion list consisting of pairs of atom
numbers is created.
For
nonbond interactions (of either Inclusion or
Exclusion type), the compile()
method also calls the update()
method.
The
update()
method does nothing for bonded terms. For nonbond
terms, the update()
method creates an inclusion list. This is an
atomnumber-based list containing pairs of atoms
that do not appear in the exclusion list, where
neither atom has a null atom type and where the
atom pair are closer together than a cutoff
distance. Since a distance criterion is used and
atomic separations change, the
update()
method should be called regularly.
Evaluating
Energy Objects
The
evaluate()
method evaluates the energy and first derivatives
from the atomnumber-based inclusion list created by
the compile()
and update()
methods. Normally the coordinates are read from the
Coordinates AtomVector
that was bound with the Energy object and the
derivatives are accumulated in the Gradients
AtomVector
that was also bound with the Energy object. If
AtomVectors
are specified in the argument list, the vectors
will be used for only that call.
Accessing
the Parameters
The
individual parameter sets can be accessed by
subscripting the Energy object using an interaction
type string as the key. The parameter set for the
given key is a tuple with a shape that is
determined by the type of Energy object, i.e., the
interaction type. New values can be assigned to an
interaction type that is present in the parameter
table. It is not possible to create new interaction
types by assignment. They can only be added to the
original parameter files. Note that each parameter
set may be used by several interactions. The new
values will change all the interactions that use
the set.
Querying
Energy Objects
Each
Energy object has several data attributes. You can
examine their values to gain some insight into the
state of the object. Some of these attributes are
writeable, i.e., you can assign new values to these
attributes. Many
of the data attributes are useful only to
programmers.
Printing
and Deleting Energy Objects
When
an Energy object is printed, the entire list of
active terms is send to the standard output.
Obviously the list can be very long. On each line
are the index numbers of the participating atoms,
the force field parameters, the current dimension
and the partial energy.
An
energy object can be deleted once it is no longer
needed. However references to the Energy object are
held in several places. The object is not removed
from memory until all the references are
deleted.
Working
with Multiple Energy Objects
It
is possible to create and use more than one
instance of a particular Inclusion type Energy
object. In order to tell them apart, they should be
given unique labels. The additional instances may
be used to isolate interactions that are being
closely studied. For example, if the parameters for
these interactions are being modified during the
simulation. By changing only these parameters, the
other interactions are not affected.
It
is not useful to have multiple instances of an
Exclusion type Energy object.
Normally,
only the Inclusion version or the Exclusion version
of an energy term is used. One would chose the
Inclusion version if there are very few
interactions and it would take more effort and
resources to exclude interactions than to include
them. The Exclusion version would be a better
choice in most situations; there are usually few
exclusions. Sometimes it is useful to use both
versions. The Inclusion version can be used to
manage the few interactions (excluded from the
Exclusion version) that will be evaluated with
different parameters in the Inclusion
object.
Dynamic
Simulations
During
a standard simulation, the energy and forces in a
molecular model changes with the evolution of the
conformation of the model. However, the force field
remains static. In a dynamic simulation (which is
not the same as molecular dynamics), not only is
the conformation changing but the force field as
well. There are several ways to change the force
field.
The
simplest way is to modify the force field
parameters: quantities like force constants and
equilibrium dimensions. This is done by subscript
assignment (above). Since the changes to the
parameter set affects all the interactions that use
the parameter, the mutating interactions are
usually isolated in separate Energy modules.
Changes to the parameters are reflected in the
evaluation of the energy and gradients immediately.
There is no need to compile.
The
force field may also be modified by modifying atom
types, atomic masses and atomic charges. These
changes do not affect the energy and gradients
until the compile()
method is called. Changes to the atomic mass only
affect molecular dynamics simulations. Changes to
atomic charges only affect the electrostatics
terms. Changes to the atom types will affect those
interactions that are based on the atom types.
Interactions that have a specific type assigned are
not affected by changes in inclusion atom
types.
The
force field is also modified by modifying the
interaction pattern or topology (using the
add(),
delete()
and modify()
methods). Since the atomnumber-based inclusion
lists are cleared by calls to the modification
methods, the compile()
method has to be called.
Finally,
the most radical changes can be made by modifying
the atom hierarchy; by adding new atoms and
deleting existing atoms. This affects the topology:
interactions involving the deleted atoms have to be
removed and added atoms introduce new Exclusion
list interactions. The biggest effect of this
change is that the AtomVectors
are no longer valid. New vectors must be created
and rebound to the Energy objects. So, in this
case, the compile()
method must be called with both arguments
specified.
|