/
masses.py
123 lines (106 loc) · 4.38 KB
/
masses.py
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
# This source code is part of the Biotite package and is distributed
# under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
# information.
__name__ = "biotite.structure.info"
__author__ = "Patrick Kunzmann"
__all__ = ["mass"]
import json
from pathlib import Path
from ..atoms import Atom, AtomArray, AtomArrayStack
from .ccd import get_from_ccd
# Masses are taken from http://www.sbcs.qmul.ac.uk/iupac/AtWt/ (2018/03/01)
ATOM_MASSES_FILE = Path(__file__).parent / "atom_masses.json"
_atom_masses = None
def mass(item, is_residue=None):
"""
Calculate the mass for the given object.
:footcite:`Meija2016`
If a residue name is given, the mass values refer to the masses of
the complete molecule without additional or missing protons.
In case of residues in a longer chain, some atoms might be missing
from the molecule.
For example non-terminal residues in a protein or nucleotide chain
miss the mass of a water molecule.
Parameters
----------
item : str or Atom or AtomArray or AtomArrayStack
The atom or molecule to get the mass for.
If a string is given, it is interpreted as residue name or
chemical element.
If an :class:`Atom` is given the mass is taken from its element.
If an :class:`AtomArray` or :class:`AtomArrayStack` is given the
mass is the sum of the mass of its atoms.
is_residue : bool, optional
If set to true and a string is given for `item`, the string
will be strictly interpreted as residue.
If set to false, the string is strictly interpreted as element.
By default the string will be interpreted as element at first
and secondly as residue name, if the element is unknown.
Returns
-------
mass : float or None
The mass of the given object in *u*. None if the mass is unknown.
References
----------
.. footbibliography::
Examples
--------
>>> print(mass(atom_array))
2170.438
>>> first_residue = list(residue_iter(atom_array))[0]
>>> print(first_residue)
A 1 ASN N N -8.901 4.127 -0.555
A 1 ASN CA C -8.608 3.135 -1.618
A 1 ASN C C -7.117 2.964 -1.897
A 1 ASN O O -6.634 1.849 -1.758
A 1 ASN CB C -9.437 3.396 -2.889
A 1 ASN CG C -10.915 3.130 -2.611
A 1 ASN OD1 O -11.269 2.700 -1.524
A 1 ASN ND2 N -11.806 3.406 -3.543
A 1 ASN H1 H -8.330 3.957 0.261
A 1 ASN H2 H -8.740 5.068 -0.889
A 1 ASN H3 H -9.877 4.041 -0.293
A 1 ASN HA H -8.930 2.162 -1.239
A 1 ASN HB2 H -9.310 4.417 -3.193
A 1 ASN HB3 H -9.108 2.719 -3.679
A 1 ASN HD21 H -11.572 3.791 -4.444
A 1 ASN HD22 H -12.757 3.183 -3.294
>>> print(mass("ASN"))
132.118
>>> first_atom = first_residue[0]
>>> print(first_atom)
A 1 ASN N N -8.901 4.127 -0.555
>>> print(mass(first_atom))
14.007
>>> print(mass("N"))
14.007
"""
global _atom_masses
with open(ATOM_MASSES_FILE, "r") as file:
_atom_masses = json.load(file)
if isinstance(item, str):
if is_residue is None:
result_mass = _atom_masses.get(item.upper())
if result_mass is None:
result_mass = get_from_ccd(
"chem_comp", item.upper(), "formula_weight"
).item()
elif not is_residue:
result_mass = _atom_masses.get(item.upper())
else:
result_mass = get_from_ccd(
"chem_comp", item.upper(), "formula_weight"
).item()
elif isinstance(item, Atom):
result_mass = mass(item.element, is_residue=False)
elif isinstance(item, AtomArray) or isinstance(item, AtomArrayStack):
result_mass = sum(
(mass(element, is_residue=False) for element in item.element)
)
else:
raise TypeError(
f"Cannot calculate mass for {type(item).__name__} objects"
)
if result_mass is None:
raise KeyError(f"{item} is not known")
return result_mass