Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified Molecular transformer example #2399

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
10 changes: 10 additions & 0 deletions applications/FLASK/Transformer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Molecular Transformer Baseline

This is an encoder-decoder transformer on SMILES data.

## Preparing the data

The data can be prepared ahead of time to simplify the pipeline

---
This example is a simplified encoder-decoder transformer in the `application/nlp` directory.
92 changes: 92 additions & 0 deletions applications/FLASK/Transformer/arg_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import argparse
import dataset_utils


# Command-line arguments
def add_transformer_architecture_arguments(args: argparse.Namespace):
"""
Adds the command line arguments to specify transformer architecture model
parameters. This is only relevant for the encoder-decoder transformer model.
"""
args.add_argument(
"--num-attention-heads",
action="store",
default=8,
type=int,
help="number of parallel attention layers (default: 8)",
metavar="NUM",
)
args.add_argument(
"--embed-dim",
action="store",
default=512,
type=int,
help="embedding space dimension (default: 512)",
metavar="NUM",
)
args.add_argument(
"--feedforward-dim",
action="store",
default=0,
type=int,
help="feedforward network dimension. If zero, set to be "
"4 times the embedding dimension (default: 0)",
metavar="NUM",
)
args.add_argument(
"--num-layers",
action="store",
default=6,
type=int,
help="Number of encoder and decoder layers (default: 6)",
metavar="NUM",
)


def add_dataset_arguments(args: argparse.Namespace, default: str):
"""
Adds dataset-related arguments to an existing argparse object.
"""
args.add_argument(
"--dataset",
type=str,
default=default,
help=f"Which dataset to use (default: {default})",
choices=dataset_utils.available_datasets(),
)
args.add_argument(
"--dataset-fraction",
action="store",
default=1.0,
type=float,
help="Fraction of dataset to use (default: 1.0)",
metavar="NUM",
)


def add_training_arguments(parser: argparse.ArgumentParser):
parser.add_argument(
"--skip-validation",
action="store_true",
default=False,
help="Do not run validation (default: false)",
)
parser.add_argument(
"--always-shuffle",
action="store_true",
default=False,
help="Always shuffle training dataset, even if pretokenized (default: false)",
)
parser.add_argument(
"--validation-set-fraction",
type=float,
default=0.01,
help="Fraction of the validation dataset to use (default: 0.001)",
)
parser.add_argument(
"--save-prototext",
action="store_true",
default=False,
help="Save prototext experiment file instead of protobin (slower but "
"debuggable) (default: false)",
)
26 changes: 26 additions & 0 deletions applications/FLASK/Transformer/dataset_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import argparse
import importlib
import os
import sys
from typing import List

dataset_dir = os.path.join(os.path.dirname(__file__), "datasets")


def available_datasets() -> List[str]:
"""
Returns the available datasets in the dataset folder.
"""
result = []
for file in os.listdir(dataset_dir):
if file.endswith(".py"):
result.append(os.path.basename(file)[:-3])
return result


def load_dataset(name: str):
"""
Loads a dataset by importing the requested module.
"""
sys.path.append(dataset_dir)
return importlib.import_module(name)
65 changes: 65 additions & 0 deletions applications/FLASK/Transformer/datasets/QM9.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
The QM9 dataset, stored as pre-tokenized binary files for optimized processing.
"""

import os
import os.path

import numpy as np
from pretokenize.SMILES_tokenizer import MolTokenizer
from pretokenize.data_utils import random_zero_array

sequence_length = int(os.getenv("QM9_SEQUENCE_LENGTH", default="32"))

# ----------------------------------------------
# Setup
# ----------------------------------------------

# Load the datasets
data_dir = os.getenv("QM9_DATA_DIR", "/p/vast1/lbann/datasets/FLASK/QM9")

tokenizer = MolTokenizer(os.path.join(data_dir, "QM9_vocab.json"))
tokenizer.load_vocab_file()

dataset_train = np.load(os.path.join(data_dir, "QM9_Pretokenized.npy"))

# dataset_train = np.zeros((140000, 32), dtype=np.float32)
_vocab_size = 46
pad_index = tokenizer.token_to_id("<pad>")
sep_index = tokenizer.token_to_id("<eos>")

# ----------------------------------------------
# Sample access functions
# ----------------------------------------------


def num_train_samples():
return dataset_train.shape[0]


def get_train_sample(i):
data = dataset_train[i]

boundary = np.where(data == sep_index)[0][0]
masked_data = random_zero_array(
data[:boundary], 0.15, tokenizer.token_to_id(tokenizer.mask_token)
)
output = np.zeros((2 * sequence_length), dtype=np.int32)
output[0:boundary] = masked_data
output[boundary] = sep_index
output[sequence_length:] = data
return output


def sample_dims():
return (2 * sequence_length + 1,)


def vocab_size():
return _vocab_size


if __name__ == "__main__":
print("Training samples:", num_train_samples())
print("Training sample 101:")
print(get_train_sample(0))
100 changes: 100 additions & 0 deletions applications/FLASK/Transformer/datasets/pretokenize/GenerateVocab.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from multiprocessing import Pool
from SMILES_tokenizer import MolTokenizer
from glob import glob
import argparse
import os
import numpy as np
from tqdm import tqdm


parser = argparse.ArgumentParser(
description="Generate vocab files for different datasets"
)

parser.add_argument(
"--qm9", action="store_true", help="Generate vocab file for QM9 dataset"
)
parser.add_argument(
"--zinc", action="store_true", help="Generate vocab file for ZINC dataset"
)
parser.add_argument(
"--pubchem", action="store_true", help="Generate vocab file for PubChem dataset"
)

args = parser.parse_args()


def join_vocabs(list_of_vocab_dicts):
"""
Given a list of vocab dictionaries, join them together
such that all unique tokens are present in the final vocab dictionary
"""
final_vocab = {}
counter = 0
for vocab in list_of_vocab_dicts:
for token in vocab.keys():
if token not in final_vocab.keys():
final_vocab[token] = counter
counter += 1
return final_vocab


def generate_zinc_vocab_dict(smi_file):
tokenizer = MolTokenizer()
with open(smi_file, "r") as f:
data = f.readlines()
for i in tqdm(range(1, len(data))):
line = data[i].split(" ")
_ = tokenizer._tokenize(line[0])
return tokenizer.vocab_dict


def main():

if args.qm9:
print("Generating vocab file for QM9 dataset")
tokenizer = MolTokenizer("QM9_vocab.json")
default_file = "/p/vast1/lbann/datasets/FLASK/QM9/QM9_smiles.txt"
qm9_file = os.getenv("QM9_FILE", default_file)
with open(qm9_file, "r") as smiles_data:
smiles_data = smiles_data.readlines()
for line in tqdm(smiles_data):
tokens = tokenizer.tokenize(line)
tokenizer.generate_vocab_file("QM9_vocab.json")
print("QM9 vocab file generated")

if args.zinc:
print("Generating vocab file for ZINC dataset")
default_dir = "/p/vast1/lbann/datasets/FLASK/ZINC"
zinc_dir = os.getenv("ZINC_DIR", default_dir)
zinc_files = glob(f"{zinc_dir}/*.smi")

print(len(zinc_files))

with Pool(20) as p:
zinc_vocab_dicts = p.map(generate_zinc_vocab_dict, zinc_files)

final_vocab = join_vocabs(zinc_vocab_dicts)

final_tokenizer = MolTokenizer("ZINC_vocab.json")
final_tokenizer.load_vocab_dict(final_vocab)
final_tokenizer.generate_vocab_file("ZINC_SMILES_vocab.json")
print("ZINC vocab file generated")

if args.pubchem:
print("Generating vocab file for PubChem dataset")
default_file = "/p/vast1/lbann/datasets/FLASK/pubchem/CID_SMILES_CANONICAL.smi"
pubchem_file = os.getenv("PUBCHEM_FILE", default_file)
with open(pubchem_file, "r") as smiles_data:
smiles_data = smiles_data.readlines()
tokenizer = MolTokenizer("PubChem_SMILES_vocab.json")
for line in tqdm(smiles_data):
smiles = line.split(" ")[1]
tokens = tokenizer.tokenize(smiles)

tokenizer.generate_vocab_file("PubChem_vocab.json")
print("PubChem vocab file generated")


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"<pad>": 0, "<eos>": 1, "<bos>": 2, "<mask>": 3, "C": 4, "(": 5, "=": 6, "O": 7, ")": 8, "[O-]": 9, "[N+]": 10, "1": 11, "N": 12, "P": 13, "c": 14, "Cl": 15, "n": 16, "2": 17, "3": 18, "4": 19, "S": 20, "#": 21, "[PH]": 22, "[nH]": 23, "[N-]": 24, "[NH4+]": 25, "[As]": 26, "-": 27, "[Br-]": 28, "Br": 29, "[Ca+2]": 30, "[C-]": 31, "[O+]": 32, "5": 33, "[Cl-]": 34, ".": 35, "[Co]": 36, "o": 37, "[n+]": 38, "[S+]": 39, "s": 40, "[SeH2]": 41, "[Hg]": 42, "[NH3+]": 43, "[HH]": 44, "I": 45, "[K+]": 46, "[SeH]": 47, "[CH3-]": 48, "[Mg+2]": 49, "[Na+]": 50, "[Ni+2]": 51, "[Ni]": 52, "[OH-]": 53, "[H+]": 54, "[Se]": 55, "[Fe+3]": 56, "[W]": 57, "[NH+]": 58, "B": 59, "[NH2+]": 60, "F": 61, "[OH+]": 62, "6": 63, "[B-]": 64, "[S-]": 65, "[Si]": 66, "[Te]": 67, "7": 68, "[Al]": 69, "8": 70, "9": 71, "%10": 72, "%11": 73, "[nH+]": 74, "[Cd]": 75, "[Pt]": 76, "[Pt+2]": 77, "[NH2-]": 78, "[Co+2]": 79, "[NH-]": 80, "[Rh+2]": 81, "[I+]": 82, "[se]": 83, "[n-]": 84, "[Ni+3]": 85, "[Fe+2]": 86, "[Li+]": 87, "[Be+2]": 88, "[F-]": 89, "[Mn+3]": 90, "[I-]": 91, "[Pr]": 92, "[Ag+]": 93, "[CH-]": 94, "[Tc+6]": 95, "[Kr]": 96, "[Hg+]": 97, "[Zn]": 98, "[SnH]": 99, "[Au+]": 100, "[Al+3]": 101, "[SiH]": 102, "[Pb]": 103, "[Sn]": 104, "[SnH2]": 105, "[AlH2]": 106, "[CH2-]": 107, "[c-]": 108, "[cH-]": 109, "[P+]": 110, "[Zn+2]": 111, "[Sr+2]": 112, "[Cu+2]": 113, "[Ce]": 114, "[Cd+2]": 115, "[Cu]": 116, "[Bi]": 117, "[BiH3]": 118, "[SiH2]": 119, "[Fe]": 120, "[Pb+2]": 121, "[Sn+2]": 122, "[SbH3]": 123, "[P-]": 124, "[Si+]": 125, "[Ce+3]": 126, "[Ba+2]": 127, "[Cs+]": 128, "[AlH4-]": 129, "[U]": 130, "[Cu+]": 131, "[Ti+4]": 132, "[Sb]": 133, "[AlH]": 134, "[Tl+]": 135, "[Hg+2]": 136, "[Rb+]": 137, "[Hg-2]": 138, "[AsH2]": 139, "[Ge]": 140, "[Mn+2]": 141, "[H]": 142, "[AsH]": 143, "[SiH3]": 144, "[Bi+3]": 145, "[Cr+2]": 146, "[La+3]": 147, "[Cr+3]": 148, "[As+]": 149, "[PbH]": 150, "[AlH3]": 151, "[C]": 152, "[Al-]": 153, "[Ga]": 154, "[Be]": 155, "[Ca]": 156, "[P-3]": 157, "[Cr]": 158, "[Mg]": 159, "[O-2]": 160, "[Sb+3]": 161, "[SH-]": 162, "[Mn]": 163, "[Mo]": 164, "[S-2]": 165, "[Th]": 166, "[V]": 167, "[U+2]": 168, "p": 169, "[Sr]": 170, "[As+3]": 171, "[Sn+]": 172, "[SnH3]": 173, "[Cl+3]": 174, "[GeH]": 175, "[Zr]": 176, "[Cl+2]": 177, "[In+3]": 178, "[TeH2]": 179, "[Nd+3]": 180, "[As-]": 181, "[Dy]": 182, "[Es]": 183, "[Ir]": 184, "[La]": 185, "[PbH2]": 186, "[Lu]": 187, "[Np]": 188, "[Nd]": 189, "[Ne]": 190, "[Nb]": 191, "[Os]": 192, "[Pd]": 193, "[Pu]": 194, "[PoH2]": 195, "[Md]": 196, "[Pm]": 197, "[Pa]": 198, "[Re]": 199, "[Rh]": 200, "[Ru]": 201, "[Sm]": 202, "[Sc]": 203, "[SiH4]": 204, "[Ag]": 205, "[Ta]": 206, "[Tc]": 207, "[Tb]": 208, "[TlH]": 209, "[Tm]": 210, "[Ti]": 211, "[Ac]": 212, "[Am]": 213, "[Ar]": 214, "[AsH3]": 215, "[Bk]": 216, "[Cm]": 217, "[Er]": 218, "[Eu]": 219, "[Gd]": 220, "[GaH3]": 221, "[GeH4]": 222, "[Au]": 223, "[Hf]": 224, "[He]": 225, "[Ho]": 226, "[Xe]": 227, "[Yb]": 228, "[Y]": 229, "[AtH]": 230, "[Cf]": 231, "[Fm]": 232, "[InH3]": 233, "[Zr+4]": 234, "[I+2]": 235, "[Se+]": 236, "[Br+2]": 237, "[Cl+]": 238, "[Al-3]": 239, "[Tl]": 240, "[CH+]": 241, "[CH]": 242, "[H-]": 243, "%12": 244, "%13": 245, "%14": 246, "%15": 247, "%16": 248, "%17": 249, "%18": 250, "%19": 251, "%20": 252, "%21": 253, "%22": 254, "%23": 255, "%24": 256, "%25": 257, "%26": 258, "%27": 259, "%28": 260, "%29": 261, "%30": 262, "%31": 263, "%32": 264, "%33": 265, "%34": 266, "%35": 267, "%36": 268, "%37": 269, "%38": 270, "[In]": 271, "[No]": 272, "[Tb+3]": 273, "[Rn]": 274, "[Lu+3]": 275, "[Pd+2]": 276, "[Eu+3]": 277, "[Dy+3]": 278, "[Ho+3]": 279, "[Au+3]": 280, "[Sm+3]": 281, "[Y+3]": 282, "[Fe-3]": 283, "[Th+4]": 284, "[Au-]": 285, "[Sn-]": 286, "[Fe-]": 287, "[Tl+3]": 288, "[Sn+3]": 289, "[BH4-]": 290, "[Ta-2]": 291, "[Ir-2]": 292, "[Cr+6]": 293, "[o+]": 294, "[Te+4]": 295, "[Lr]": 296, "[N]": 297, "[V+2]": 298, "[Ga+3]": 299, "[Pt+4]": 300, "[Si-]": 301, "[Gd+3]": 302, "[Tc+3]": 303, "[Co+3]": 304, "[Pd-2]": 305, "[Pt-2]": 306, "[Sn+4]": 307, "[Er+3]": 308, "[Pd+]": 309, "[Se-2]": 310, "[Yb+3]": 311, "[Zn-2]": 312, "[O]": 313, "[Ta+5]": 314, "[Ba]": 315, "[Sc+3]": 316, "[SbH]": 317, "[Se+4]": 318, "[PH2-]": 319, "[Si+4]": 320, "[I+3]": 321, "[Ru+2]": 322, "[Ce+4]": 323, "[GeH2]": 324, "[Tm+3]": 325, "[Sb+]": 326, "[Se-]": 327, "[Ti+]": 328, "[Os+2]": 329, "[Ir+3]": 330, "[Ru+3]": 331, "[Pr+3]": 332, "[Na]": 333, "[K]": 334, "[Li]": 335, "[Rh+3]": 336, "[InH]": 337, "[Cs]": 338, "[Rb]": 339, "[Yb+2]": 340, "[Pt+]": 341, "[Ti+2]": 342, "[Mo+2]": 343, "[Ti+3]": 344, "[OH2+]": 345, "[Zr+2]": 346, "[C+]": 347, "[IrH+2]": 348, "[Mo+4]": 349, "[Eu+2]": 350, "[AlH2+]": 351, "[As+5]": 352, "[Sb-]": 353, "[Se+6]": 354, "[Cr+5]": 355, "[PH2]": 356, "[V+4]": 357, "[Ru+5]": 358, "[Li-]": 359, "[s+]": 360, "[AlH+2]": 361, "[c]": 362, "[BH3-]": 363, "[CH2]": 364, "[SnH4]": 365, "[S]": 366, "[PbH4]": 367, "[TeH]": 368, "[NH2]": 369, "[OH3+]": 370, "[At]": 371, "[te]": 372, "[siH]": 373, "[ReH]": 374, "[WH2]": 375, "[MoH2]": 376, "[GeH3]": 377, "[NH]": 378, "[B]": 379, "[AgH]": 380, "[TlH3]": 381, "[BH2]": 382, "[SH2+]": 383, "[Hf+4]": 384, "[Nb+5]": 385, "[FeH2]": 386, "[Cr+4]": 387, "[TaH2]": 388, "[GaH2]": 389, "[GaH]": 390, "[Th+2]": 391, "[P]": 392, "[SH]": 393, "[IH]": 394, "[si]": 395, "[Rh-]": 396, "[SH+]": 397, "[Rh+]": 398, "[Ru-]": 399, "[Rh-2]": 400, "[cH+]": 401, "[Tc+4]": 402, "[OH]": 403, "[Ru+]": 404, "[InH2]": 405, "[Zn-]": 406, "[Nb+2]": 407, "[Ru+4]": 408, "[Os+4]": 409, "[pH]": 410, "[Br+]": 411, "[PH4+]": 412, "[SiH3-]": 413, "[Zr-]": 414, "[Cu-2]": 415, "[Ta+2]": 416, "[Zr+3]": 417, "[Ni-]": 418, "[Al-2]": 419, "[Ru-2]": 420, "[CH2+]": 421, "[Ag-]": 422, "[BiH]": 423, "[Hg-]": 424, "[Tc+7]": 425, "[Os+8]": 426, "[Br+3]": 427, "[SbH2]": 428, "[Mo+3]": 429, "[BiH2]": 430, "[b-]": 431, "[Zn+]": 432, "[Fe+]": 433, "[Ru+6]": 434, "[BH-]": 435, "[Ni+]": 436, "[BH2-]": 437, "[Co+]": 438, "[PtH]": 439, "[Os+6]": 440, "[Te+]": 441, "[Bi+2]": 442, "[RuH]": 443, "[ZrH]": 444, "[SiH-]": 445, "[Ru+8]": 446, "[IH2+]": 447, "[ClH+]": 448, "[ClH2+]": 449, "[Os+7]": 450, "[SH3+]": 451, "[Os+]": 452, "[Tc+]": 453, "[Tc+5]": 454, "[IH+]": 455, "[PH+]": 456, "[Ru-3]": 457, "[W+2]": 458, "[PH2+]": 459, "[FeH]": 460, "[CoH2]": 461, "[W+]": 462, "[Fe+6]": 463, "[NiH]": 464, "[OsH]": 465, "[CH3+]": 466, "[p-]": 467, "[se+]": 468, "[PH-]": 469, "[I]": 470, "[Br]": 471, "[PH3+]": 472, "[CH3]": 473, "[Cu-]": 474, "[PbH2+2]": 475, "[Mn+]": 476, "[Ir+2]": 477, "[sH+]": 478, "[Cd-2]": 479, "[CuH]": 480, "[Re-]": 481, "[Re-2]": 482, "[TlH2]": 483, "[SeH2+]": 484, "[Ga-]": 485, "[Ir+]": 486, "[RhH]": 487, "[Gd+2]": 488, "[ZrH2]": 489, "[Os+5]": 490, "[Ni-2]": 491, "[Rh-3]": 492, "[RhH+2]": 493, "[Hf+2]": 494, "[Mn-2]": 495, "[Cr+]": 496, "[c+]": 497, "[Co-2]": 498, "[Nb-2]": 499, "[Fe-2]": 500, "[OsH2]": 501, "[PtH2]": 502, "[WH]": 503, "[RhH2]": 504, "[Ti-2]": 505, "[Bi+]": 506, "[SeH+]": 507, "[Al+2]": 508, "[SeH-]": 509, "[Nb+3]": 510, "[TaH]": 511, "[In-]": 512, "[Pt-]": 513, "[Tc+2]": 514, "[Nb-]": 515, "[Mo+]": 516, "[Ta-]": 517, "[Al+]": 518, "[NbH2]": 519, "[Pd-]": 520, "[FeH6-4]": 521, "[MoH]": 522, "[W-]": 523, "[In+]": 524, "[SbH+]": 525, "[AsH3+]": 526, "[Cl]": 527, "[F]": 528, "[PbH3]": 529, "[SnH3-]": 530, "[SeH3+]": 531, "[SeH3]": 532, "[TeH3+]": 533, "[TeH3]": 534, "[Ni-3]": 535, "[SbH4+]": 536, "[SbH4]": 537, "[AsH4+]": 538, "[PH-2]": 539, "[AsH3-]": 540, "[AsH2+]": 541, "[Cr-3]": 542, "[Cr-2]": 543, "[Fe-4]": 544, "[Mo-2]": 545, "[SiH2-]": 546, "[SiH2+]": 547, "[SnH2+]": 548, "[BiH2+2]": 549, "[Os-]": 550, "[PtH+]": 551, "[SbH5]": 552, "[p+]": 553, "[Po]": 554, "[Ra]": 555, "[Fr]": 556, "[AlH-]": 557, "[AlH2-]": 558, "[RuH+2]": 559, "[SnH+3]": 560, "[BiH2+]": 561, "[AsH-]": 562, "[RuH2+2]": 563, "[BH]": 564, "[Os-2]": 565, "[SiH3+]": 566, "[SnH3+]": 567, "[TeH2+]": 568, "[AsH5]": 569, "[TeH+]": 570, "[Si+3]": 571, "b": 572, "[Cr-]": 573, "[si+2]": 574, "[Si+2]": 575, "[Zr+]": 576, "[Co-]": 577, "[Ir-3]": 578, "[Mg+]": 579, "[V+]": 580, "[Bi-]": 581, "[Tb+4]": 582, "[P-2]": 583, "[SnH+2]": 584, "[Fe+5]": 585, "[Fe+4]": 586, "[BiH5]": 587, "[RuH+]": 588, "[RuH2]": 589, "[AlH6-3]": 590, "[IrH3]": 591, "[IrH4]": 592, "[ReH2]": 593, "[NbH3]": 594, "[RuH3]": 595, "[ReH3]": 596, "[IrH]": 597, "[IrH2]": 598, "[ZnH2]": 599, "[CrH2]": 600, "[LaH3]": 601, "[SmH3]": 602, "[EuH3]": 603, "[OsH-]": 604, "[WH4]": 605, "[MoH5]": 606, "[si+]": 607, "[RuH4]": 608, "[TaH3]": 609, "[MoH3]": 610, "[FeH4]": 611, "[MoH4]": 612, "[HgH2]": 613, "[ThH2]": 614, "[TiH2]": 615, "[AuH]": 616, "[ZrH3]": 617, "[si-]": 618, "[ReH7]": 619, "[UH2]": 620, "[OsH4]": 621, "[GaH4-]": 622, "[ThH4]": 623, "[WH6]": 624, "[oH+]": 625, "[RuH6]": 626, "[PdH2]": 627, "[PtH4]": 628, "[NiH2]": 629, "[VH2]": 630, "[PtH3]": 631, "[RhH3]": 632, "[UH3]": 633, "[MnH2]": 634, "[CuH2]": 635, "[CoH3]": 636, "[FeH3]": 637, "[TiH4]": 638, "[RuH5]": 639, "[bH-]": 640, "[BiH4]": 641, "[ReH4]": 642, "[HgH]": 643, "[WH3]": 644, "[CeH3]": 645, "[SnH2+2]": 646, "[Si-2]": 647, "%39": 648, "%40": 649, "%41": 650, "%42": 651, "%43": 652, "%44": 653, "%45": 654, "%46": 655, "%47": 656, "%48": 657, "%49": 658, "%50": 659, "%51": 660, "%52": 661, "%53": 662, "%54": 663, "%55": 664, "%56": 665, "%57": 666, "%58": 667, "%59": 668, "%60": 669, "%61": 670, "%62": 671, "[Hf+]": 672, "[al+]": 673, "[SnH+]": 674, "[Bi-2]": 675, "[AlH3-]": 676, "[PtH2+2]": 677, "[Zr-2]": 678, "[ClH4+3]": 679, "[pH+]": 680, "[Co-3]": 681, "%63": 682, "%64": 683, "%65": 684, "%66": 685, "%67": 686, "%68": 687, "%69": 688, "%70": 689, "%71": 690, "%72": 691, "%73": 692, "%74": 693, "[Pr+]": 694, "[te+]": 695, "[Os-3]": 696, "[al]": 697, "[PdH+]": 698, "[Ti-]": 699, "[SH2]": 700, "[BiH4-]": 701, "[TeH4]": 702, "[Zr-4]": 703, "[Zr-3]": 704, "[Ta+]": 705, "[U+4]": 706, "[U+3]": 707, "[ZrH2+2]": 708, "[Bh]": 709, "[Hs]": 710, "[Rf]": 711, "[Mt]": 712, "[Sg]": 713, "[Db]": 714, "[AsH4]": 715, "[UH]": 716, "[YH2]": 717, "[YH]": 718, "%75": 719, "%76": 720, "%77": 721, "%78": 722, "%79": 723, "%80": 724, "%81": 725, "%82": 726, "%83": 727, "%84": 728, "%85": 729, "%86": 730, "[RuH+3]": 731, "%87": 732, "%88": 733, "%89": 734, "%90": 735, "%91": 736, "%92": 737, "[Ca+]": 738, "[Ba+]": 739, "[MnH]": 740, "[ZnH+]": 741, "%93": 742, "%94": 743, "%95": 744, "%96": 745, "%97": 746, "%98": 747, "%99": 748, "0": 749, "[CuH+]": 750, "[TiH+3]": 751, "[VH]": 752, "[ClH2+2]": 753, "[Ge+4]": 754, "[Sb+5]": 755, "[SeH5]": 756, "[AlH+]": 757, "[ClH3+2]": 758, "[TiH]": 759, "[TiH+]": 760, "[ClH3+3]": 761, "[ClH+2]": 762, "[Cd-]": 763, "[PdH]": 764, "[siH+]": 765, "[SiH+]": 766, "[XeH]": 767, "[siH-]": 768, "[KrH]": 769, "[AsH+]": 770, "[AsH2-]": 771, "[SiH4-]": 772, "[SnH2-]": 773, "[YbH2]": 774, "[CrH+2]": 775, "[CuH2-]": 776, "[CoH+]": 777, "*": 778, "[Cf+3]": 779, "[CoH+2]": 780, "[MnH+]": 781, "[CeH]": 782, "[NiH2+2]": 783, "[PoH]": 784, "[SnH-]": 785, "[SiH+2]": 786, "[ClH2+3]": 787, "[SbH3+]": 788, "[AuH3]": 789, "[XeH2]": 790, "[B+]": 791, "[TaH5]": 792, "[FeH4-]": 793, "[FeH6-3]": 794, "[ScH3]": 795, "[Ru-4]": 796, "[SbH2+]": 797, "[RuH-]": 798}
Loading
Loading