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
|
"""Contains functions to manipulate i.e. modify macromolecular entities."""
from numpy import array
from itertools import izip
from cogent.core.entity import HIERARCHY, copy, StructureHolder, ModelHolder
from cogent.maths.geometry import coords_to_symmetry, coords_to_crystal
from cogent.struct.selection import einput
__author__ = "Marcin Cieslik"
__copyright__ = "Copyright 2009, The Cogent Project"
__credits__ = ["Marcin Cieslik"]
__license__ = "GPL"
__version__ = "1.5.0"
__maintainer__ = "Marcin Cieslik"
__email__ = "mpc4p@virginia.edu"
__status__ = "Development"
def clean_ical(entities, pretend=True, mask=True):
"""Removes or masks entities with ambiguous (i)nsertion (c)odes or
(a)lternate (l)ocations.
Arguments:
- entities: universal input see: ``cogent.struct.selection.einput``
- pretend: If ``True`` only reports icals and does not mask or remove
anything.
- mask (boolean): If pretend is ``False`` masks entities instead of
removing them.
This function does not check for occupancy. I retains the residue which is
first when sorted by id number, insertion code and finally name. Residues
without IC come first. Atoms within a retained residue are sorted according
to PDB rules and the first one is chosen. If The first entity has an IC or
alt_loc different from ' ' it will be changed to ' '.
"""
conflicts = []
changes = []
residues = einput(entities, 'R')
id_r = [[None, None, None]]
for r in residues.sortedvalues(): # sort by id, ic, name
id_a = [[None, None]]
if r.res_id == id_r[0][1]: # on collision choose first ...
conflicts.append(r.getFull_id())
if not pretend:
if mask:
r.setMasked(True)
else:
r.parent.delChild(r.id)
continue # an entity could be in other holders
# keep it there as-is
for a in r.sortedvalues(): # sort by id, alt_loc (' ', 'A' ...)
if a.at_id == id_a[0][0]: # on collision choose first
conflicts.append(a.getFull_id())
if not pretend:
if mask:
a.setMasked(True)
else:
r.delChild(a.id)
else:
if a.id[0][1] != ' ':
changes.append((a.getFull_id(), ((a.id[0][0], ' '),)))
if not pretend:
a.setAlt_loc(' ')
try:
a.parent.updateIds()
except AttributeError:
pass
id_a = a.id
if r.id[0][2] != ' ':
changes.append((r.getFull_id(), ((r.id[0][0], r.id[0][1], ' '),)))
if not pretend:
r.set_res_ic(' ')
try:
r.parent.updateIds()
except AttributeError:
pass
id_r = r.id
return (changes, conflicts)
def expand_symmetry(model, mode='uc', name='UC', **kwargs):
"""Applies the symmetry operations defined by the header of the PDB files to
the given ``Model`` entity instance. Returns a ``ModelHolder`` entity.
Arguments:
- model: model entity to expand
- mode: 'uc', 'bio' or 'raw'
- name: optional name of the ``ModelHolder`` instance.
Requires a PDB file with a correct CRYST1 field and space group information.
"""
structure = model.getParent('S')
sh = structure.header
fmx = sh['uc_fmx']
omx = sh['uc_omx']
mxs = sh['uc_mxs']
# get initial coordinates
atoms = einput(model, 'A')
coords = array(atoms.getData('coords'))
# expand the coordinates to symmetry
all_coords = coords_to_symmetry(coords, fmx, omx, mxs, mode)
models = ModelHolder(name)
for i in xrange(0, len(mxs)):
# copy model
new_model = copy(model) # with additional models which
new_atoms = einput(new_model, 'A')
# patch with coordinates
new_coords = all_coords[i]
for (atom_id, new_coord) in izip(atoms.keys(), new_coords):
new_atoms[atom_id[1:]].coords = new_coord
# give it an id: the models are numbered by the symmetry operations with
# identity being the first model
new_model.setName(i)
models.addChild(new_model)
return models
def expand_crystal(structure, n=1, name='XTAL'):
"""Expands the contents of a structure to a crystal of a given size. Returns
a `` StructureHolder`` entity instance.
Arguments:
- structure: ``Structure`` entity instance.
- n: number number of unit-cell layers.
- name: optional name.
Requires a PDB file with correct CRYST1 field and space group information.
"""
sh = structure.header
sn = structure.name
fmx = sh['uc_fmx']
omx = sh['uc_omx']
# get initial coorinates
atoms = einput(structure, 'A')
coords = array([atoms.getData('coords')]) # fake 3D
# expand the coordinates to crystal
all_coords = coords_to_crystal(coords, fmx, omx, n)
structures = StructureHolder(name)
rng = range(-n, n + 1) # a range like -2, -1, 0, 1, 2
vectors = [(x, y, z) for x in rng for y in rng for z in rng]
for i, (u, v, w) in enumerate(vectors):
new_structure = copy(structure)
new_atoms = einput(new_structure, 'A')
new_coords = all_coords[i, 0]
for (atom_id, new_coord) in izip(atoms.keys(), new_coords):
new_atoms[atom_id].coords = new_coord
new_structure.setName("%s_%s%s%s" % (sn, u, v, w))
structures.addChild(new_structure)
return structures
|