/usr/share/pyshared/MMTK/NucleicAcids.py is in python-mmtk 2.7.9-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | # This module implements classes for nucleotide chains.
#
# Written by Konrad Hinsen
#
"""
Nucleic acid chains
"""
__docformat__ = 'restructuredtext'
from MMTK import Biopolymers, Bonds, ChemicalObjects, Collections, \
ConfigIO, Database, Universe, Utility
from Scientific.Geometry import Vector
from MMTK.Biopolymers import defineNucleicAcidResidue
#
# Nucleotides are special groups
#
class Nucleotide(Biopolymers.Residue):
"""
Nucleic acid residue
Nucleotides are a special kind of group. Like any other
group, they are defined in the chemical database. Each residue
has two or three subgroups ('sugar' and 'base', plus 'phosphate'
except for 5'-terminal residues) and is usually
connected to other residues to form a nucleotide chain. The database
contains three variants of each residue (5'-terminal, 3'-terminal,
non-terminal).
"""
def __init__(self, name = None, model = 'all'):
"""
:param name: the name of the nucleotide in the chemical database. This
is the full name of the residue plus the suffix
"_5ter" or "_3ter" for the terminal variants.
:type name: str
:param model: one of "all" (all-atom), "none" (no hydrogens),
"polar" (united-atom with only polar hydrogens),
"polar_charmm" (like "polar", but defining
polar hydrogens like in the CHARMM force field).
Currently the database has definitions only for "all".
:type model: str
"""
if name is not None:
blueprint = _residueBlueprint(name, model)
ChemicalObjects.Group.__init__(self, blueprint)
self.model = model
self._init()
def backbone(self):
"""
:returns: the sugar and phosphate groups
:rtype: :class:`~MMTK.ChemicalObjects.Group`
"""
bb = self.sugar
if hasattr(self, 'phosphate'):
bb = Collections.Collection([bb, self.phosphate])
return bb
def bases(self):
"""
:returns: the base group
:rtype: :class:`~MMTK.ChemicalObjects.Group`
"""
return self.base
def _residueBlueprint(name, model):
try:
blueprint = _residue_blueprints[(name, model)]
except KeyError:
if model == 'polar':
name = name + '_uni'
elif model == 'polar_charmm':
name = name + '_uni2'
elif model == 'none':
name = name + '_noh'
blueprint = Database.BlueprintGroup(name)
_residue_blueprints[(name, model)] = blueprint
return blueprint
_residue_blueprints = {}
#
# Nucleotide chains are molecules with added features.
#
class NucleotideChain(Biopolymers.ResidueChain):
"""
Nucleotide chain
Nucleotide chains consist of nucleotides that are linked together.
They are a special kind of molecule, i.e. all molecule operations
are available.
Nucleotide chains act as sequences of residues. If n is a NucleotideChain
object, then
* len(n) yields the number of nucleotides
* n[i] yields nucleotide number i
* n[i:j] yields the subchain from nucleotide number i up to but
excluding nucleotide number j
"""
def __init__(self, sequence, **properties):
"""
:param sequence: the nucleotide sequence. This can be a string
containing the one-letter codes, or a list
of two-letter codes (a "d" or "r" for the type of
sugar, and the one-letter base code), or a
:class:`~MMTK.PDB.PDBNucleotideChain` object.
If a PDBNucleotideChain object is supplied, the
atomic positions it contains are assigned to the
atoms of the newly generated nucleotide chain,
otherwise the positions of all atoms are undefined.
:keyword model: one of "all" (all-atom), "no_hydrogens" or "none"
(no hydrogens), "polar_hydrogens" or "polar"
(united-atom with only polar hydrogens),
"polar_charmm" (like "polar", but defining
polar hydrogens like in the CHARMM force field),
"polar_opls" (like "polar", but defining
polar hydrogens like in the latest OPLS force field).
Default is "all". Currently the database contains
definitions only for "all".
:type model: str
:keyword terminus_5: if True, the first residue is constructed
using the 5'-terminal variant, if False the
non-terminal version is used. Default is True.
:type terminus_5: bool
:keyword terminus_3: if True, the last residue is constructed
using the 3'-terminal variant, if False the
non-terminal version is used. Default is True.
:type terminus_3: bool
:keyword circular: if True, a bond is constructed
between the first and the last residue.
Default is False.
:type circular: bool
:keyword name: a name for the chain (a string)
:type name: str
"""
if sequence is not None:
hydrogens = self.binaryProperty(properties, 'hydrogens', 'all')
if hydrogens == 1:
hydrogens = 'all'
elif hydrogens == 0:
hydrogens = 'none'
term5 = self.binaryProperty(properties, 'terminus_5', True)
term3 = self.binaryProperty(properties, 'terminus_3', True)
circular = self.binaryProperty(properties, 'circular', False)
try:
model = properties['model'].lower()
except KeyError:
model = hydrogens
self.version_spec = {'hydrogens': hydrogens,
'terminus_5': term5,
'terminus_3': term3,
'model': model,
'circular': circular}
if isinstance(sequence[0], basestring):
conf = None
else:
conf = sequence
sequence = [r.name for r in sequence]
sequence = [Biopolymers._fullName(r) for r in sequence]
if term5:
if sequence[0].find('5ter') == -1:
sequence[0] += '_5ter'
if term3:
if sequence[-1].find('3ter') == -1:
sequence[-1] += '_3ter'
self.groups = []
n = 0
for residue in sequence:
n += 1
r = Nucleotide(residue, model)
r.name = r.symbol + '_' + `n`
r.sequence_number = n
r.parent = self
self.groups.append(r)
self._setupChain(circular, properties, conf)
is_nucleotide_chain = True
def __getslice__(self, first, last):
return NucleotideSubChain(self, self.groups[first:last])
def backbone(self):
"""
:returns: the sugar and phosphate groups of all nucleotides
:rtype: :class:`~MMTK.Collections.Collection`
"""
bb = Collections.Collection([])
for residue in self.groups:
try:
bb.addObject(residue.phosphate)
except AttributeError:
pass
bb.addObject(residue.sugar)
return bb
def bases(self):
"""
:returns: the base groups of all nucleotides
:rtype: :class:`~MMTK.Collections.Collection`
"""
return Collections.Collection([r.base for r in self.groups])
def _descriptionSpec(self):
kwargs = ','.join([name + '=' + `self.version_spec[name]`
for name in sorted(self.version_spec.keys())])
return "N", kwargs
def _typeName(self):
return ''.join([s.ljust(3) for s in self.sequence()])
def _graphics(self, conf, distance_fn, model, module, options):
if model != 'backbone':
return ChemicalObjects.Molecule._graphics(self, conf,
distance_fn, model,
module, options)
color = options.get('color', 'black')
material = module.EmissiveMaterial(color)
objects = []
for i in range(1, len(self.groups)-1):
a1 = self.groups[i].phosphate.P
a2 = self.groups[i+1].phosphate.P
p1 = a1.position(conf)
p2 = a2.position(conf)
if p1 is not None and p2 is not None:
bond_vector = 0.5*distance_fn(a1, a2, conf)
cut = bond_vector != 0.5*(p2-p1)
if not cut:
objects.append(module.Line(p1, p2, material = material))
else:
objects.append(module.Line(p1, p1+bond_vector,
material = material))
objects.append(module.Line(p2, p2-bond_vector,
material = material))
return objects
#
# Subchains are created by slicing chains or extracting a chain from
# a group of connected chains.
#
class NucleotideSubChain(NucleotideChain):
"""
A contiguous part of a nucleotide chain
NucleotideSubChain objects are the result of slicing operations on
NucleotideChain objects. They cannot be created directly.
NucleotideSubChain objects permit all operations of NucleotideChain
objects, but cannot be added to a universe.
"""
def __init__(self, chain, groups, name = ''):
self.groups = groups
self.atoms = []
self.bonds = []
for g in self.groups:
self.atoms = self.atoms + g.atoms
self.bonds = self.bonds + g.bonds
for i in range(len(self.groups)-1):
self.bonds.append(Bonds.Bond((self.groups[i].sugar.O_3,
self.groups[i+1].phosphate.P)))
self.bonds = Bonds.BondList(self.bonds)
self.name = name
self.parent = chain.parent
self.type = None
self.configurations = {}
self.part_of = chain
is_incomplete = True
def __repr__(self):
if self.name == '':
return 'SubChain of ' + repr(self.part_of)
else:
return ChemicalObjects.Molecule.__repr__(self)
__str__ = __repr__
#
# Type check functions
#
def isNucleotideChain(x):
"Returns True if x is a NucleotideChain."
return hasattr(x, 'is_nucleotide_chain')
|