import json
import re
import io
from dataclasses import dataclass, field, asdict
from typing import List, Tuple, Dict, DefaultDict, TextIO
@dataclass
class Isotope:
mass: float
abundance: float
neutrons: int
@dataclass
class Element:
symbol: str
element_number: int
most_abundant_isotope: int
monoisotope: int
isotopes: Dict[int, Isotope] = field(default_factory=dict)
def to_dict(self) -> dict:
state = asdict(self)
return state
@dataclass
class Entry:
symbol: str
element_number: int
mass_number: int
mass: float
abundance: float
@dataclass
class NISTParser:
elements: Dict[str, Element] = field(default_factory=dict)
def parse(self, stream: TextIO):
buffer = {}
for line in stream:
line = line.strip()
if line.startswith("#"):
continue
if not line:
if buffer:
self.process_buffer(buffer)
buffer.clear()
else:
k, v = line.split(" =")
v = v.strip()
buffer[k] = v
if buffer:
self.process_buffer(buffer)
buffer.clear()
def process_buffer(self, buffer: Dict[str, str]):
entry = Entry(
symbol=buffer["Atomic Symbol"],
element_number=int(buffer["Atomic Number"]),
mass_number=int(buffer["Mass Number"]),
mass=float(buffer["Relative Atomic Mass"].split("(")[0]),
abundance=float(buffer["Isotopic Composition"].split("(")[0] or 0.0),
)
if entry.symbol not in self.elements:
monoisotope = None
weights = buffer['Standard Atomic Weight'][1:-1].split(",")
if len(weights) == 1:
monoisotope = int(weights[0])
element = Element(
entry.symbol,
element_number=entry.element_number,
most_abundant_isotope=None,
monoisotope=monoisotope,
)
self.elements[entry.symbol] = element
else:
element = self.elements[entry.symbol]
iso = Isotope(
entry.mass, entry.abundance, entry.mass_number
)
element.isotopes[iso.neutrons] = iso
def index_isotopes(self):
for sym, element in self.elements.items():
if not element.monoisotope:
most_abundant_isoform = max(element.values(), key=lambda x: x.abundance)
def write_json(self, stream: TextIO):
json.dump(
{k: v.to_dict() for k, v in self.elements.items()},
stream,
sort_keys=True,
indent=2,
)
if __name__ == "__main__":
import sys
parser = NISTParser()
parser.parse(sys.stdin)
parser.write_json(sys.stdout)