"vscode:/vscode.git/clone" did not exist on "5b5a7909c0bbcd6d15b6e89f67e40881c9d7541c"
Commit 8bcff367 authored by Jason Swails's avatar Jason Swails
Browse files

Drastically improve performance of getElementByMass

The old approach iterated through the entire periodic table by atomic number and
subtracted the provided mass by the element's mass and kept track of the
smallest difference. The new approach steps through the elements in order of
atomic number and bails once it hits an element with a higher mass than the
target mass (assuming masses are monotonically increasing).

On my desktop, processing 4TVP-dmj_wat-ion.psf dropped from 297 s to 15.4 s. But
15.4 s is still a bit too long...
parent 5e7370c0
...@@ -47,6 +47,7 @@ class Element(object): ...@@ -47,6 +47,7 @@ class Element(object):
_elements_by_symbol = {} _elements_by_symbol = {}
_elements_by_atomic_number = {} _elements_by_atomic_number = {}
_max_atomic_number = 0
def __init__(self, number, name, symbol, mass): def __init__(self, number, name, symbol, mass):
"""Create a new element """Create a new element
...@@ -67,6 +68,8 @@ class Element(object): ...@@ -67,6 +68,8 @@ class Element(object):
self._mass = mass self._mass = mass
# Index this element in a global table # Index this element in a global table
s = symbol.strip().upper() s = symbol.strip().upper()
## Keep track of the largest atomic number
Element._max_atomic_number = max(Element._max_atomic_number, number)
assert s not in Element._elements_by_symbol assert s not in Element._elements_by_symbol
Element._elements_by_symbol[s] = self Element._elements_by_symbol[s] = self
...@@ -96,6 +99,17 @@ class Element(object): ...@@ -96,6 +99,17 @@ class Element(object):
""" """
Get the element whose mass is CLOSEST to the requested mass. This method Get the element whose mass is CLOSEST to the requested mass. This method
should not be used for repartitioned masses should not be used for repartitioned masses
Parameters
----------
mass : float or Quantity
Mass of the atom to find the element for. Units assumed to be
daltons if not specified
Returns
-------
element : Element
The element whose atomic mass is closest to the input mass
""" """
# Assume masses are in daltons if they are not units # Assume masses are in daltons if they are not units
if not is_quantity(mass): if not is_quantity(mass):
...@@ -103,13 +117,18 @@ class Element(object): ...@@ -103,13 +117,18 @@ class Element(object):
diff = mass diff = mass
best_guess = None best_guess = None
for key in Element._elements_by_atomic_number: for atnum in xrange(1, Element._max_atomic_number+1):
element = Element._elements_by_atomic_number[key] element = Element._elements_by_atomic_number[atnum]
massdiff = abs(element.mass - mass) massdiff = abs(element.mass - mass)
if massdiff < diff: if massdiff < diff:
best_guess = element best_guess = element
diff = massdiff diff = massdiff
if element.mass > mass:
# Elements are only getting heavier, so bail out early
return best_guess
# This really should only happen if we wanted ununoctium or something
# bigger... won't really happen but still make sure we return an Element
return best_guess return best_guess
@property @property
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment