no edit summary
'''A new paradigm for describing structural
fragments in molecules'''
This text describes the basic principles of the '''
MotiveQuery''' language for describing structural fragments in molecules. First, the text puts two approaches for identifying molecular fragments in contrast: the imperative approach, and the declarative one, taken by the ''' MotiveQuery''' language. Next, basic principles of the language are illustrated on several examples and later described in a more formal way. Finally, the original example is revisited and explained in the terms of the newly introduced concepts.
==Example, Part One==
Let’s assume we have loaded a protein stored in a PDB or mmCIF file with correctly annotated HET groups.
The characteristics of an imperative approach is explicitly stating steps that need to be performed in order achieve a particular goal. In contrast a declarative approach states the goal we would like to achieve, leaving the individual steps as an "implementation detail".
In the declarative approach, our code would look like this:
Internally, the function <code>[[
MotiveQuery:Language_Reference#AmbientAtoms | AmbientAtoms()]]</code> might run code similar to the imperative version. However, what is important is that this complexity is hidden from the user when the declarative approach is used.
Now, let’s extend our example even further: "all HET residues and atoms within 4A around them, where the entire structure contains at least one calcium atom".
We will not bother the reader with writing down the imperative version - implementing the condition "at least one calcium atom" is rather boring. However, using the declarative approach, the description of the
fragment becomes simply:
As we've seen in the example above, it is very easy to ''compose'' our ideas about the final shape of the
fragment we are interested in. The way this works is that the input molecule is decomposed into a stream of fragments. These streams can then be modified and combined into new streams, which can be modified and combined again.
As an example, take the query <code>Atoms('Ca')</code>. What the '''
MotiveQuery''' language does is to extract all calcium atoms from the input molecule and represent them as a stream of sets containing one atom each as illustrated on the image below:
Now, each element of this stream can be modified, for example to include all atoms 4A within the original calcium atom. Now we have a stream of sets of atoms, where each set contains the original Ca atom and the atoms within the given radius. This would be represented by the query <code>Atoms('Ca').AmbientAtoms(4)</code> and is illustrated on the image bellow:
MotiveQuery-Principles Atoms(Ca) surr.png|center|600px]] In the next step, we might wish to keep only these fragments that contain at least 6 atoms. This is achieved by looking at each fragment, counting the number of atoms and throwing away these fragments that do not meet the criteria. Written as a query, this could be represented as <code>Atoms('Ca').AmbientAtoms(4).Filter(lambda m: m.Count(Atoms()) >= 6)</code>. In the graphical form:
Image:Near .png| center|600px]]
===A More Formal Description===
There are two basic data structures that the language is built upon. These are:
Fragment'''. A fragment is simple an arbitrary set of atoms.* ''' Fragment Sequence'''. A sequence of fragments. In mathematical terms, can be understood as a "set of fragments" which is another way of saying "set of sets of atoms".
And on these data structures, there are three basic types of queries:
* '''Generator queries'''. Generator queries, as the name suggests, generate sequences of
fragments from the original input. They are the tool that transforms the input molecule into a stream of fragments that can be later modified or combined. Examples of these queries include <code>[[ MotiveQuery:Language_Reference#Atoms | Atoms()]]</code>, <code>[[ MotiveQuery:Language_Reference#Residues | Residues()]]</code>, and <code>[[ MotiveQuery:Language_Reference#RegularMotifs | RegularMotifs()]]</code>.* '''Modifier queries'''. These queries operate on individual fragments and modify them or throw them away. Examples include <code>[[ MotiveQuery:Language_Reference#AmbientAtoms | AmbientAtoms()]]</code>, <code>[[ MotiveQuery:Language_Reference#ConnectedResidues | ConnectedResidues()]]</code>, and <code>[[ MotiveQuery:Language_Reference#Filter | Filter()]]</code>.* '''Combinator queries'''. Combinatorial queries take as input two or more sequence of fragments and combine them into a single new sequence that satisfies given criteria. Examples include <code>[[ MotiveQuery:Language_Reference# Near | Near()]]</code>, <code>[[ MotiveQuery:Language_Reference# Cluster | Cluster()]]</code>, and <code>[[ MotiveQuery:Language_Reference# Star | Star()]]</code>.
This corresponds to the following process.
# A generator query <code>[[
MotiveQuery:Language_Reference#HetResidues | HetResidues()]]</code> is executed that produces a sequence of fragments that are composed of atoms corresponding to HET residues.# Next, the original sequence is modified by adding atoms within 3 angstrom from any original atom to each fragment.# Finally, each fragment in the modified sequence is examined: all “calcium atom fragments” are identified and counted. Only these fragments that contain at least 1 Ca atom are kept.
MotiveQuery:Language_Reference#HetResidues | HetResidues()]]</code> .[[Image: MotiveQuery-Principles- HetResidues.png| center|500px]]
MotiveQuery:Language_Reference#Filter | .Filter(lambda l: l.Count(Atoms('Ca')) > 0)]]</code>[[Image: MotiveQuery-Principles-AmbientAtoms-filter.png| center|500px]]