Files
2026-08-03 18:42:47 +08:00

148 lines
4.4 KiB
Python

'''
Experimental MMTF (Macromolecular Transmission Format) support
'''
as_str = lambda s: s if isinstance(s, str) else s.decode("utf-8")
#####################################################################
ss_map = {
0: 'H', # pi helix
1: 'L', # bend
2: 'H', # alpha helix
3: 'S', # extended
4: 'H', # 3-10 helix
5: 'S', # bridge
6: 'L', # turn
7: 'L', # coil
}
#####################################################################
def _to_chempy(data, use_auth=True):
'''
Construct a "chempy" model (molecule) from decoded MMTF data.
'''
from itertools import islice, zip_longest
from chempy import models, Atom, Bond
def add_bond(i1, i2, order, offset=0):
bond = Bond()
bond.order = order
bond.index = [i1 + offset, i2 + offset]
model.add_bond(bond)
coord_iter = data.get_table_iter([
'xCoordList',
'yCoordList',
'zCoordList',
])
atom_iter = data.get_table_iter([
'bFactorList',
'occupancyList',
'altLocList',
'atomIdList',
], [0.0, 1.0, '', -1])
group_iter = data.get_table_iter([
'groupTypeList',
'sequenceIndexList',
'groupIdList',
'insCodeList',
'secStructList',
])
chain_list_iter = enumerate(data.get_table_iter([
'chainIdList',
'chainNameList',
'groupsPerChain',
]))
groupList = data.get('groupList')
symmetry = (
data.get('unitCell', None),
as_str(data.get('spaceGroup', '')),
)
model_output = []
for n_chains in data.get_iter('chainsPerModel'):
model = models.Indexed()
model_output.append(model)
if symmetry[0] is not None:
model.cell, model.spacegroup = symmetry
for (chain_idx, (segi, chain, n_groups)) in islice(chain_list_iter, n_chains):
for (groupType, label_seq_id, auth_seq_id, ins_code, ss_info) in \
islice(group_iter, n_groups):
group = groupList[groupType]
resn = as_str(group['groupName'])
bondAtomList_iter = iter(group.get('bondAtomList', ()))
group_bond_iter = zip_longest(
bondAtomList_iter,
bondAtomList_iter,
group.get('bondOrderList', ()),
)
offset = len(model.atom)
for (i1, i2, order) in group_bond_iter:
add_bond(i1, i2, order, offset)
group_atom_iter = zip(
group['atomNameList'],
group['elementList'],
group['formalChargeList'],
)
for (name, elem, formal_charge) in group_atom_iter:
atom = Atom()
(atom.b, atom.q, atom.alt, atom.id) = next(atom_iter)
atom.coord = next(coord_iter)
atom.symbol = as_str(elem)
atom.name = as_str(name)
atom.resn = resn
atom.hetatm = label_seq_id == -1
atom.formal_charge = formal_charge
atom.segi = segi
atom.chain = chain
atom.ss = ss_map.get(ss_info, '')
if use_auth or label_seq_id is None:
atom.resi = auth_seq_id
atom.ins_code = ins_code or ''
else:
atom.resi = label_seq_id + 1
model.add_atom(atom)
model_atom_max = 0
model_atom_min = 0
model_iter = iter(model_output)
bondAtomList_iter = data.get_iter('bondAtomList')
for i1, i2, order in zip_longest(bondAtomList_iter,
bondAtomList_iter,
data.get_iter('bondOrderList'),
fillvalue=1):
if i1 >= model_atom_max or i2 >= model_atom_max:
model = next(model_iter)
model_atom_min = model_atom_max
model_atom_max += len(model.atom)
add_bond(i1, i2, order, -model_atom_min)
return model_output
#####################################################################
from .io import MmtfReader
MmtfReader.to_chempy = _to_chempy
#####################################################################