Source code for eon.atoms


""" The atoms module. """
from eon.config import config

from math import cos, sin, acos
import numpy
import logging
logger = logging.getLogger('atoms')

[docs] class Atoms: """ The Atoms class. """ def __init__(self, n_atoms): self.r = numpy.zeros((n_atoms,3)) self.free = numpy.ones(n_atoms) self.box = numpy.zeros((3,3)) self.names = ['']*n_atoms self.mass = numpy.zeros(n_atoms) def __len__(self): ''' Returns the number of atoms in the object''' return len(self.r)
[docs] def copy(self): p = Atoms(len(self)) p.r = self.r.copy() p.free = self.free.copy() p.box = self.box.copy() p.names = self.names[:] p.mass = self.mass.copy() return p
[docs] def free_r(self): nfree = sum(self.free) temp = numpy.zeros((nfree, 3)) index = 0 for i in range(len(self.r)): if self.free[i]: temp[index] = self.r[i] index += 1 return temp
[docs] def append(self, r, free, name, mass): self.r = numpy.append(self.r, [r], 0) self.free = numpy.append(self.free, free) self.names.append(name) self.mass = numpy.append(self.mass, mass)
[docs] def pbc(r, box, ibox = None): """ Applies periodic boundary conditions. Parameters: r: the vector the boundary conditions are applied to box: the box that defines the boundary conditions ibox: the inverse of the box. This will be calcluated if not provided. """ if ibox is None: ibox = numpy.linalg.inv(box) vdir = numpy.dot(r, ibox) vdir = (vdir % 1.0 + 1.5) % 1.0 - 0.5 return numpy.dot(vdir, box)
[docs] def per_atom_norm(v, box, ibox = None): ''' Returns a length N numpy array containing per atom distance v: an Nx3 numpy array box: box matrix that defines the boundary conditions ibox: the inverse of the box. will be calculated if not provided ''' diff = pbc(v, box, ibox) return numpy.sqrt(numpy.sum(diff**2.0, axis=1))
[docs] def per_atom_norm_gen(v, box, ibox = None): ''' Returns a generator which yields the distance between pairs of atoms v: an Nx3 numpy array box: box matrix that defines the boundary conditions ibox: the inverse of the box. will be calculated if not provided ''' diff = pbc(v, box, ibox) for d in diff: yield numpy.linalg.norm(d)
[docs] def get_process_atoms(r, p, epsilon_r=0.2, nshells=1): ''' Given the reactant and product configurations of a process, return the atoms that move significantly and their neighbors along the trajectory. ''' mobileAtoms = [] r2p = per_atom_norm(p.r - r.r, r.box) for i in range(len(r)): if r2p[i] > epsilon_r: mobileAtoms.append(i) if len(mobileAtoms) == 0: mobileAtoms.append(list(r2p).index(max(r2p))) neighborAtoms = [] for atom in mobileAtoms: r1 = elements[r.names[atom]]["radius"] for i in range(len(r)): if i in mobileAtoms or i in neighborAtoms: continue r2 = elements[r.names[i]]["radius"] maxDist = (r1 + r2) * (1.0 + 0.2)*nshells if numpy.linalg.norm(pbc(p.r[atom] - p.r[i], p.box)) < maxDist: neighborAtoms.append(i) return mobileAtoms + neighborAtoms
[docs] def identical(atoms1, atoms2): ''' Determines whether two structures are identical if atoms of the same element are considered indistinguishable. atoms1: first atoms object for comparison atoms2: second atoms object for comparison epsilon_r: distance (in angstroms) that two atoms must be seperated by in order to be considered different ''' #XXX: n^2 epsilon_r = config.comp_eps_r if len(atoms1) != len(atoms2): return False for i in range(3): for j in range(3): #XXX: Hardcoded comparison criteria if abs(atoms1.box[i][j] - atoms2.box[i][j]) > .0001: logger.warning("Identical returned false because boxes were not the same") return False box = atoms1.box ibox = numpy.linalg.inv(box) mismatch = [] pan = per_atom_norm(atoms1.r - atoms2.r, box, ibox) for i in range(len(pan)): if pan[i] > epsilon_r: mismatch.append(i) elif atoms1.names[i] != atoms2.names[i]: return False for i in mismatch: pan = per_atom_norm(atoms1.r - atoms2.r[i], box, ibox) minpan = 1e300 minj = 0 for j in range(len(pan)): if i == j: continue if pan[j] < minpan: minpan = pan[j] minj = j if not (minpan < epsilon_r and atoms1.names[minj] == atoms2.names[i]): return False return True
[docs] def brute_neighbor_list(p, cutoff): nl = [] ibox = numpy.linalg.inv(p.box) for a in range(len(p)): nl.append([]) for b in range(len(p)): if b != a: dist = numpy.linalg.norm(pbc(p.r[a] - p.r[b], p.box, ibox)) if dist < cutoff: nl[a].append(b) return nl
[docs] def sweep_and_prune(p_in, cutoff, strict = True, bc = True): """ Returns a list of nearest neighbors within cutoff for each atom. Parameters: p_in: Atoms object cutoff: the radius within which two atoms are considered to intersect. strict: perform an actual distance check if True bc: include neighbors across pbc's """ #TODO: Get rid of 'cutoff' and use the covalent bond radii. (Rye can do) # Do we want to use covalent radii? I think the displace class wants to allow for user-defined cutoffs. # We should have both options available. -Rye #TODO: Make work for nonorthogonal boxes. p = p_in.copy() p.r = pbc(p.r, p.box) p.r -= numpy.array([min(p.r[:,0]), min(p.r[:,1]), min(p.r[:,2])]) numatoms = len(p) coord_list = [] for i in range(numatoms): coord_list.append([i, p.r[i]]) for axis in range(3): sorted_axis = sorted(coord_list, key = lambda foo: foo[1][axis]) intersect_axis = [] for i in range(numatoms): intersect_axis.append([]) for i in range(numatoms): done = False j = i + 1 if not bc and j >= numatoms: done = True while not done: j = j % numatoms if j == i: done = True dist = abs(sorted_axis[j][1][axis] - sorted_axis[i][1][axis]) if p.box[axis][axis] - sorted_axis[i][1][axis] < cutoff: dist = min(dist, (p.box[axis][axis] - sorted_axis[i][1][axis]) + sorted_axis[j][1][axis]) if dist < cutoff: intersect_axis[sorted_axis[i][0]].append(sorted_axis[j][0]) intersect_axis[sorted_axis[j][0]].append(sorted_axis[i][0]) j += 1 if not bc and j >= numatoms: done = True else: done = True if axis == 0: intersect = [] for i in range(numatoms): intersect.append([]) intersect[i] = intersect_axis[i] else: for i in range(numatoms): intersect[i] = list(set(intersect[i]).intersection(intersect_axis[i])) if strict: ibox = numpy.linalg.inv(p.box) for i in range(numatoms): l = intersect[i][:] for j in l: dist = numpy.linalg.norm(pbc(p.r[i] - p.r[j], p.box, ibox)) if dist > cutoff: intersect[i].remove(j) intersect[j].remove(i) return intersect
[docs] def neighbor_list(p, cutoff, brute=False): if brute: nl = brute_neighbor_list(p, cutoff) else: nl = sweep_and_prune(p, cutoff) return nl
[docs] def neighbor_list_vectors(p, cutoff, brute=False): '''Points from center to neighbor''' nl = neighbor_list(p, cutoff, brute=brute) nl_vec = [] ibox = numpy.linalg.inv(p.box) for center_index in range(len(p)): nl_vec.append([]) for neighbor_index in nl[center_index]: vec = pbc(p.r[neighbor_index] - p.r[center_index], p.box, ibox) nl_vec[center_index].append(vec) return nl_vec
[docs] def coordination_numbers(p, cutoff, brute=False): """ Returns a list of coordination numbers for each atom in p """ nl = neighbor_list(p, cutoff, brute) return [len(l) for l in nl]
[docs] def least_coordinated(p, cutoff, brute=False): """ Returns a list of atom indices in p with the lowest coordination numbers for unfrozen atoms""" cn = coordination_numbers(p, cutoff, brute) maxcoord = max(cn) mincoord = min(cn) while mincoord <= maxcoord: least = [] for i in range(len(cn)): if cn[i] <= mincoord and p.free[i]: least.append(i) if len(least) > 0: return least mincoord += 1
[docs] def match(a,b,eps_r,neighbor_cutoff,indistinguishable): if len(a)!=len(b): return False if config.comp_check_rotation: if indistinguishable and config.comp_use_identical: return get_mappings(a,b,eps_r,neighbor_cutoff) else: return rot_match(a,b) else: if indistinguishable and config.comp_use_identical: return identical(a,b) else: diff = pbc(a.r-b.r, a.box) return numpy.max(numpy.sum(diff**2.0, axis=1)) < eps_r**2.0
#return max(per_atom_norm(a.r-b.r, a.box))<eps_r
[docs] def point_energy_match(file_a, energy_a, file_b, energy_b): import eon.fileio as io if abs(energy_a - energy_b) > config.comp_eps_e: return False a = io.loadcon(file_a) b = io.loadcon(file_b) if match(a, b, config.comp_eps_r, config.comp_neighbor_cutoff, False): return True
[docs] def points_energies_match(file_a, energy_a, files_b, energies_b): for i in range(len(files_b)): if point_energy_match(file_a, energy_a, files_b[i], energies_b[i]): return i return None
[docs] def rot_match(a, b): if not (a.free.all() and b.free.all()): logger.warning("Comparing structures with frozen atoms with rotational matching; check_rotation may be set incorrectly") acm = sum(a.r)/len(a) bcm = sum(b.r)/len(b) # SVD algorithm ("Least-Squares Fitting of Two 3-D Point Sets" by Arun, Huang, and Blostein) ta_r = a.r - acm tb_r = b.r - bcm H = numpy.dot(ta_r.transpose() , tb_r) U, S, V = numpy.linalg.svd(H) R = numpy.dot(U, V) if numpy.linalg.det(R) < 0: V[2] *= -1 R = numpy.dot(U, V) ta_r = numpy.dot(ta_r, R) dist = max(numpy.linalg.norm(ta_r - tb_r, axis=1)) return dist < config.comp_eps_r ''' Quaternion algorithm ta = a.copy() tb = b.copy() ta.r -= acm tb.r -= bcm #Horn, J. Opt. Soc. Am. A, 1987 m = numpy.dot(tb.r.transpose(), ta.r) sxx = m[0][0] sxy = m[0][1] sxz = m[0][2] syx = m[1][0] syy = m[1][1] syz = m[1][2] szx = m[2][0] szy = m[2][1] szz = m[2][2] n = numpy.zeros((4,4)) n[0][1] = syz-szy n[0][2] = szx-sxz n[0][3] = sxy-syx n[1][2] = sxy+syx n[1][3] = szx+sxz n[2][3] = syz + szy n += n.transpose() n[0][0] = sxx + syy + szz n[1][1] = sxx-syy-szz n[2][2] = -sxx + syy -szz n[3][3] = -sxx -syy + szz w,v = numpy.linalg.eig(n) maxw = 0 maxv = 0 for i in range(len(w)): if w[i] > maxw: maxw = w[i] maxv = v[:,i] R = numpy.zeros((3,3)) aa = maxv[0]**2 bb = maxv[1]**2 cc = maxv[2]**2 dd = maxv[3]**2 ab = maxv[0]*maxv[1] ac = maxv[0]*maxv[2] ad = maxv[0]*maxv[3] bc = maxv[1]*maxv[2] bd = maxv[1]*maxv[3] cd = maxv[2]*maxv[3] R[0][0] = aa + bb - cc - dd R[0][1] = 2*(bc-ad) R[0][2] = 2*(bd+ac) R[1][0] = 2*(bc+ad) R[1][1] = aa - bb + cc - dd R[1][2] = 2*(cd-ab) R[2][0] = 2*(bd-ac) R[2][1] = 2*(cd+ab) R[2][2] = aa - bb - cc + dd tb.r = numpy.dot(tb.r, R.transpose()) dist = max(per_atom_norm(ta.r - tb.r, ta.box)) return dist < config.comp_eps_r '''
### This gives the RMSD faster, but does not give the optimial rotation ### this could be amended by solving for the eigenvector corresponding to the largest eigenvalue ### Theobald, Acta Crystallographica A, 2005 # ##could be faster if done explicitly #c0 = numpy.linalg.det(k) #c1 = -8*numpy.linalg.det(m) #c2 = -2*numpy.trace(numpy.dot(m.transpose(), m)) #ga = numpy.trace(numpy.dot(ta.r.transpose(), ta.r)) #gb = numpy.trace(numpy.dot(tb.r.transpose(), tb.r)) # #lold = 0.0 #l = (ga + gb)/2.0 #while abs(lold - l) > 0.00001: # lold = l # l -= (l**4 + c2*l**2 + c1*l + c0)/(4*l**3 + 2*c2*l + c1) #rmsd = sqrt((ga + gb - 2*l)/len(a)) #return rmsd < config.comp_rot_rmsd
[docs] def rotm(axis, theta): ''' Gives the matrix representing a rotation of theta radians about axis ''' u = axis[0] v = axis[1] w = axis[2] u2 = u*u v2 = v*v w2 = w*w ct = cos(theta) st = sin(theta) mag = numpy.linalg.norm(axis) if (mag*mag == 0 or theta == 0.0): return numpy.identity(3) return numpy.array([ [u2 +(v2 +w2)*ct, u*v*(1-ct)-w*mag*st, u*w*(1-ct)+v*mag*st], [u*v*(1-ct)+w*mag*st, v2 +(u2 +w2)*ct, v*w*(1-ct)-u*mag*st], [u*w*(1-ct)-v*mag*st, v*w*(1-ct)+u*mag*st, w2 +(v2 +u2)*ct] ])/(mag*mag)
[docs] def cna(p, cutoff, brute=False): """ Returns a list of cna numbers for all atoms in p Inspired by the CNA code provided by Asap (wiki.fysik.dtu.dk/asap)""" can_values = numpy.zeros(len(p)) nr_FCC = numpy.zeros(len(p)) nr_HCP = numpy.zeros(len(p)) nl = neighbor_list(p, cutoff, brute) # loops over all the atoms for a2 in range(len(p)): nl_a2 = nl[a2] # loops over the atoms neighboring a2 for n2 in range(len(nl_a2)): a1 = nl_a2[n2]; if a1 < a2: common = [] nl_a1 = nl[a1] # loops over the atoms neighboring a1 for n1 in range(len(nl_a1)): a3 = nl_a1[n1] # checks if atom a_3 is a common neighbor to a1 and a2 for m2 in range(len(nl_a2)): if a3 == nl_a2[m2]: common.append(a3) # determines the connectivity of common neighbors if len(common) == 4: bonds_nr = 0 bonds_sum = 0 for j2 in range(1,4): nl_j2 = nl[common[j2]] for j1 in range(j2): for n in range(len(nl_j2)): if common[j1] == nl_j2[n]: bonds_nr += 1 bonds_sum += j1 + j2 if bonds_nr == 2: if bonds_sum == 6: nr_FCC[a1] += 1 nr_FCC[a2] += 1 else: nr_HCP[a1] += 1 nr_HCP[a2] += 1 # 2: fcc (421), 1: hcp (422), 0: other for i in range(len(p)): if len(nl[i]) == 12: if nr_FCC[i] == 12: can_values[i] = 2 elif (nr_FCC[i] == 6) and (nr_HCP[i] == 6): can_values[i] = 1 return can_values
[docs] def not_HCP_or_FCC(p, cutoff, brute=False): """ Returns a list of indices for the atoms with cna = 0 """ not_cna = [] cna_numbers = cna(p, cutoff, brute) for i in range(len(cna_numbers)): if cna_numbers[i] == 0: not_cna.append(i) return not_cna
# ### TShacked start
[docs] def cnat(p, cutoff, brute=False): """ Returns a list of cna numbers for all atoms in p Inspired by the CNA code provided by Asap (wiki.fysik.dtu.dk/asap)""" can_values = numpy.zeros(len(p)) nr_5 = numpy.zeros(len(p)) nr_6 = numpy.zeros(len(p)) nl = neighbor_list(p, cutoff, brute) # loops over all the atoms for a2 in range(len(p)): nl_a2 = nl[a2] # loops over the atoms neighboring a2 for n2 in range(len(nl_a2)): a1 = nl_a2[n2]; if a1 < a2: common = [] nl_a1 = nl[a1] # loops over the atoms neighboring a1 for n1 in range(len(nl_a1)): a3 = nl_a1[n1] # checks if atom a_3 is a common neighbor to a1 and a2 for m2 in range(len(nl_a2)): if a3 == nl_a2[m2]: common.append(a3) # determines the connectivity of common neighbors #print a2, n2, len(common) if len(common) in [5,6]: bonds_nr = 0 bonds_sum = 0 for j2 in range(1,len(common)): nl_j2 = nl[common[j2]] for j1 in range(j2): for n in range(len(nl_j2)): if common[j1] == nl_j2[n]: bonds_nr += 1 bonds_sum += j1 + j2 if bonds_nr == 5 and len(common) == 5: nr_5[a1] += 1 nr_5[a2] += 1 elif bonds_nr == 6 and len(common) == 6: nr_6[a1] += 1 nr_6[a2] += 1 # 1: CN12, 2: CN14, 3: CN15, 4: CN16, 5: BCC, 0: other for i in range(len(p)): if nr_5[i] == 12: if len(nl[i]) == 12: can_values[i] = 1 if (len(nl[i]) == 14) and (nr_6[i] == 2): can_values[i] = 2 if (len(nl[i]) == 15) and (nr_6[i] == 3): can_values[i] = 3 if (len(nl[i]) == 16) and (nr_6[i] == 4): can_values[i] = 4 if nr_5[i] == 0: if nr_6[i] == 8 and len(nl[i]) == 14: can_values[i] = 5 return can_values
[docs] def cnar(p, cutoff, brute=False): """ Returns a list of cna numbers for all atoms in p Inspired by the CNA code provided by Asap (wiki.fysik.dtu.dk/asap)""" # not compatible with older python versions #cna = {i:{} for i in range(len(p))} # make a dict of dicts for each atom. cna = {} for i in range(len(p)): cna[i] = {} nl = neighbor_list(p, cutoff, brute) def codeString(j,k,l): return "%d,%d,%d" % (j,k,l) # loops over all the atoms for a2 in range(len(p)): nl_a2 = nl[a2] # loops over the atoms neighboring a2 for n2 in range(len(nl_a2)): a1 = nl_a2[n2]; if a1 < a2: # prevent double counting? common = [] nl_a1 = nl[a1] # loops over the atoms neighboring a1 for n1 in range(len(nl_a1)): a3 = nl_a1[n1] # checks if atom a_3 is a common neighbor to a1 and a2 for m2 in range(len(nl_a2)): if a3 == nl_a2[m2]: common.append(a3) # determines the connectivity of common neighbors bonds_nr = 0 bonds_sum = 0 for j2 in range(1,len(common)): nl_j2 = nl[common[j2]] for j1 in range(j2): for n in range(len(nl_j2)): if common[j1] == nl_j2[n]: bonds_nr += 1 bonds_sum += j1 + j2 code = codeString(len(common), bonds_nr, bonds_sum) if not code in cna[a1]: cna[a1][code] = 0 cna[a1][code] += 1 if not code in cna[a2]: cna[a2][code] = 0 cna[a2][code] += 1 return cna
[docs] def not_TCP(p, cutoff, brute=False): """ Returns a list of indices for the atoms with cna = 0 """ not_cna = [] cna_numbers = cnat(p, cutoff, brute) for i in range(len(cna_numbers)): if cna_numbers[i] == 0 or cna_numbers[i] == 5: not_cna.append(i) return not_cna
[docs] def not_TCP_or_BCC(p, cutoff, brute=False): """ Returns a list of indices for the atoms with cna = 0 """ not_cna = [] cna_numbers = cnat(p, cutoff, brute) for i in range(len(cna_numbers)): if cna_numbers[i] == 0: not_cna.append(i) return not_cna
import sys sys.setrecursionlimit(10000)
[docs] def get_mappings(a, b, eps_r, neighbor_cutoff, mappings = None): """ A recursive depth-first search for a complete set of mappings from atoms in configuration a to atoms in configuration b. Do not use the mappings argument, this is only used internally for recursion. Returns None if no mapping was found, or a dictionary mapping atom indices a to atom indices b. Note: If a and b are mirror images, this function will still return a mapping from a to b, even though it may not be possible to align them through translation and rotation. """ # If this is the top-level user call, create and loop through top-level # mappings. if mappings is None: # Find the least common coordination number in b. bCoordinations = coordination_numbers(b, neighbor_cutoff) bCoordinationsCounts = {} for coordination in bCoordinations: if coordination in bCoordinationsCounts: bCoordinationsCounts[coordination] += 1 else: bCoordinationsCounts[coordination] = 1 bLeastCommonCoordination = list(bCoordinationsCounts.keys())[0] for coordination in list(bCoordinationsCounts.keys()): if bCoordinationsCounts[coordination] < bCoordinationsCounts[bLeastCommonCoordination]: bLeastCommonCoordination = coordination # Find one atom in a with the least common coordination number in b. # If it does not exist, return None. aCoordinations = coordination_numbers(a, neighbor_cutoff) try: aAtom = aCoordinations.index(bLeastCommonCoordination) except ValueError: return None # Create a mapping from the atom chosen from a to each of the atoms with # the least common coordination number in b, and recurse. for i in range(len(bCoordinations)): if bCoordinations[i] == bLeastCommonCoordination: # Make sure the element types are the same. if a.names[aAtom] != b.names[i]: continue mappings = get_mappings(a, b, eps_r, neighbor_cutoff, {aAtom:i}) # If the result is not none, then we found a successful mapping. if mappings is not None: return mappings # There were no mappings. return None # This is a recursed invocation of this function. else: # Find an atom from a that has not yet been mapped. unmappedA = 0 while unmappedA < len(a): if unmappedA not in list(mappings.keys()): break unmappedA += 1 # Calculate the distances from unmappedA to all mapped a atoms. distances = {} for i in list(mappings.keys()): distances[i] = numpy.linalg.norm(pbc(a.r[unmappedA] - a.r[i], a.box)) # Loop over each unmapped b atom. Compare the distances between it and # the mapped b atoms to the corresponding distances between unmappedA # and the mapped atoms. If everything is similar, create a new mapping # and recurse. for bAtom in range(len(b)): if bAtom not in list(mappings.values()): for aAtom in distances: # Break if type check fails. if b.names[bAtom] != a.names[unmappedA]: break # Break if distance check fails bDist = numpy.linalg.norm(pbc(b.r[bAtom] - b.r[mappings[aAtom]], b.box)) if abs(distances[aAtom] - bDist) > eps_r: break else: # All distances were good, so create a new mapping. newMappings = mappings.copy() newMappings[unmappedA] = bAtom # If this is now a complete mapping from a to b, return it. if len(newMappings) == len(a): return newMappings # Otherwise, recurse. newMappings = get_mappings(a, b, eps_r, neighbor_cutoff, newMappings) # Pass any successful mapping up the recursion chain. if newMappings is not None: return newMappings # There were no mappings. return None
[docs] def get_rotation_matrix(axis, theta): axis = axis / numpy.linalg.norm(axis) t = theta T = 1.0 - cos(t) rx, ry, rz = axis rotmat = numpy.zeros((3, 3)) rotmat[0][0] = T*rx*rx + cos(t) rotmat[0][1] = T*ry*rx + rz*sin(t) rotmat[0][2] = T*rz*rx - ry*sin(t) rotmat[1][0] = T*rx*ry - rz*sin(t) rotmat[1][1] = T*ry*ry + cos(t) rotmat[1][2] = T*rz*ry + rx*sin(t) rotmat[2][0] = T*rx*rz + ry*sin(t) rotmat[2][1] = T*ry*rz - rx*sin(t) rotmat[2][2] = T*rz*rz + cos(t) return rotmat
[docs] def rotate(r, axis, center, angle): new_r = r.copy() if abs(angle) == 0.0: return new_r rotmat = get_rotation_matrix(axis, angle) center = center.copy() new_r -= center new_r = numpy.dot(new_r, rotmat) new_r += center return new_r
[docs] def internal_motion(a, b): """ Takes two atoms objects and returns the motion from a to b that is entirely internal - no rotation or translation, in the form of a new atoms object. """ b = b.copy() b.r -= a.r[0] - b.r[0] a0a1 = (a.r[1] - a.r[0]) / numpy.linalg.norm(a.r[1] - a.r[0]) b0b1 = (b.r[1] - b.r[0]) / numpy.linalg.norm(b.r[1] - b.r[0]) axis1 = numpy.cross(b0b1, a0a1) / numpy.linalg.norm(numpy.cross(b0b1, a0a1)) theta1 = acos((a0a1*b0b1).sum()) b.r = rotate(b.r, axis1, a.r[0], theta1) axis2 = (a.r[2] - a.r[0]) / numpy.linalg.norm(a.r[2] - a.r[0]) va = a.r[2] - ((a.r[2] - a.r[0]) * axis2).sum() * axis2 va = va / numpy.linalg.norm(va) vb = b.r[2] - ((b.r[2] - a.r[0]) * axis2).sum() * axis2 vb = vb / numpy.linalg.norm(vb) theta2 = acos((va * vb).sum()) b.r = rotate(b.r, axis2, a.r[0], theta2) return b
elements = {} numElements = 119 elements[ 0] = elements[ 'Xx'] = {'symbol': 'Xx', 'name': 'unknown', 'mass': 1.00000000, 'radius': 1.0000, 'color': [1.000, 0.078, 0.576], 'number': 0} elements[ 1] = elements[ 'H'] = {'symbol': 'H', 'name': 'hydrogen', 'mass': 1.00794000, 'radius': 0.3100, 'color': [1.000, 1.000, 1.000], 'number': 1} elements[ 2] = elements[ 'He'] = {'symbol': 'He', 'name': 'helium', 'mass': 4.00260200, 'radius': 0.2800, 'color': [0.851, 1.000, 1.000], 'number': 2} elements[ 3] = elements[ 'Li'] = {'symbol': 'Li', 'name': 'lithium', 'mass': 6.94100000, 'radius': 1.2800, 'color': [0.800, 0.502, 1.000], 'number': 3} elements[ 4] = elements[ 'Be'] = {'symbol': 'Be', 'name': 'beryllium', 'mass': 9.01218200, 'radius': 0.9600, 'color': [0.761, 1.000, 0.000], 'number': 4} elements[ 5] = elements[ 'B'] = {'symbol': 'B', 'name': 'boron', 'mass': 10.81100000, 'radius': 0.8400, 'color': [1.000, 0.710, 0.710], 'number': 5} elements[ 6] = elements[ 'C'] = {'symbol': 'C', 'name': 'carbon', 'mass': 12.01070000, 'radius': 0.7300, 'color': [0.565, 0.565, 0.565], 'number': 6} elements[ 7] = elements[ 'N'] = {'symbol': 'N', 'name': 'nitrogen', 'mass': 14.00670000, 'radius': 0.7100, 'color': [0.188, 0.314, 0.973], 'number': 7} elements[ 8] = elements[ 'O'] = {'symbol': 'O', 'name': 'oxygen', 'mass': 15.99940000, 'radius': 0.6600, 'color': [1.000, 0.051, 0.051], 'number': 8} elements[ 9] = elements[ 'F'] = {'symbol': 'F', 'name': 'fluorine', 'mass': 18.99840320, 'radius': 0.5700, 'color': [0.565, 0.878, 0.314], 'number': 9} elements[ 10] = elements[ 'Ne'] = {'symbol': 'Ne', 'name': 'neon', 'mass': 20.17970000, 'radius': 0.5800, 'color': [0.702, 0.890, 0.961], 'number': 10} elements[ 11] = elements[ 'Na'] = {'symbol': 'Na', 'name': 'sodium', 'mass': 22.98976928, 'radius': 1.6600, 'color': [0.671, 0.361, 0.949], 'number': 11} elements[ 12] = elements[ 'Mg'] = {'symbol': 'Mg', 'name': 'magnesium', 'mass': 24.30500000, 'radius': 1.4100, 'color': [0.541, 1.000, 0.000], 'number': 12} elements[ 13] = elements[ 'Al'] = {'symbol': 'Al', 'name': 'aluminum', 'mass': 26.98153860, 'radius': 1.2100, 'color': [0.749, 0.651, 0.651], 'number': 13} elements[ 14] = elements[ 'Si'] = {'symbol': 'Si', 'name': 'silicon', 'mass': 28.08550000, 'radius': 1.1100, 'color': [0.941, 0.784, 0.627], 'number': 14} elements[ 15] = elements[ 'P'] = {'symbol': 'P', 'name': 'phosphorus', 'mass': 30.97376200, 'radius': 1.0700, 'color': [1.000, 0.502, 0.000], 'number': 15} elements[ 16] = elements[ 'S'] = {'symbol': 'S', 'name': 'sulfur', 'mass': 32.06500000, 'radius': 1.0500, 'color': [1.000, 1.000, 0.188], 'number': 16} elements[ 17] = elements[ 'Cl'] = {'symbol': 'Cl', 'name': 'chlorine', 'mass': 35.45300000, 'radius': 1.0200, 'color': [0.122, 0.941, 0.122], 'number': 17} elements[ 18] = elements[ 'Ar'] = {'symbol': 'Ar', 'name': 'argon', 'mass': 39.94800000, 'radius': 1.0600, 'color': [0.502, 0.820, 0.890], 'number': 18} elements[ 19] = elements[ 'K'] = {'symbol': 'K', 'name': 'potassium', 'mass': 39.09830000, 'radius': 2.0300, 'color': [0.561, 0.251, 0.831], 'number': 19} elements[ 20] = elements[ 'Ca'] = {'symbol': 'Ca', 'name': 'calcium', 'mass': 40.07800000, 'radius': 1.7600, 'color': [0.239, 1.000, 0.000], 'number': 20} elements[ 21] = elements[ 'Sc'] = {'symbol': 'Sc', 'name': 'scandium', 'mass': 44.95591200, 'radius': 1.7000, 'color': [0.902, 0.902, 0.902], 'number': 21} elements[ 22] = elements[ 'Ti'] = {'symbol': 'Ti', 'name': 'titanium', 'mass': 47.86700000, 'radius': 1.6000, 'color': [0.749, 0.761, 0.780], 'number': 22} elements[ 23] = elements[ 'V'] = {'symbol': 'V', 'name': 'vanadium', 'mass': 50.94150000, 'radius': 1.5300, 'color': [0.651, 0.651, 0.671], 'number': 23} elements[ 24] = elements[ 'Cr'] = {'symbol': 'Cr', 'name': 'chromium', 'mass': 51.99610000, 'radius': 1.3900, 'color': [0.541, 0.600, 0.780], 'number': 24} elements[ 25] = elements[ 'Mn'] = {'symbol': 'Mn', 'name': 'manganese', 'mass': 54.93804500, 'radius': 1.3900, 'color': [0.611, 0.478, 0.780], 'number': 25} elements[ 26] = elements[ 'Fe'] = {'symbol': 'Fe', 'name': 'iron', 'mass': 55.84500000, 'radius': 1.3200, 'color': [0.878, 0.400, 0.200], 'number': 26} elements[ 27] = elements[ 'Co'] = {'symbol': 'Co', 'name': 'cobalt', 'mass': 58.69340000, 'radius': 1.2600, 'color': [0.941, 0.565, 0.627], 'number': 27} elements[ 28] = elements[ 'Ni'] = {'symbol': 'Ni', 'name': 'nickel', 'mass': 58.93319500, 'radius': 1.2400, 'color': [0.314, 0.816, 0.314], 'number': 28} elements[ 29] = elements[ 'Cu'] = {'symbol': 'Cu', 'name': 'copper', 'mass': 63.54600000, 'radius': 1.3200, 'color': [0.784, 0.502, 0.200], 'number': 29} elements[ 30] = elements[ 'Zn'] = {'symbol': 'Zn', 'name': 'zinc', 'mass': 65.38000000, 'radius': 1.2200, 'color': [0.490, 0.502, 0.690], 'number': 30} elements[ 31] = elements[ 'Ga'] = {'symbol': 'Ga', 'name': 'gallium', 'mass': 69.72300000, 'radius': 1.2200, 'color': [0.761, 0.561, 0.561], 'number': 31} elements[ 32] = elements[ 'Ge'] = {'symbol': 'Ge', 'name': 'germanium', 'mass': 72.64000000, 'radius': 1.2000, 'color': [0.400, 0.561, 0.561], 'number': 32} elements[ 33] = elements[ 'As'] = {'symbol': 'As', 'name': 'arsenic', 'mass': 74.92160000, 'radius': 1.1900, 'color': [0.741, 0.502, 0.890], 'number': 33} elements[ 34] = elements[ 'Se'] = {'symbol': 'Se', 'name': 'selenium', 'mass': 78.96000000, 'radius': 1.2000, 'color': [1.000, 0.631, 0.000], 'number': 34} elements[ 35] = elements[ 'Br'] = {'symbol': 'Br', 'name': 'bromine', 'mass': 79.90400000, 'radius': 1.2000, 'color': [0.651, 0.161, 0.161], 'number': 35} elements[ 36] = elements[ 'Kr'] = {'symbol': 'Kr', 'name': 'krypton', 'mass': 83.79800000, 'radius': 1.1600, 'color': [0.361, 0.722, 0.820], 'number': 36} elements[ 37] = elements[ 'Rb'] = {'symbol': 'Rb', 'name': 'rubidium', 'mass': 85.46780000, 'radius': 2.2000, 'color': [0.439, 0.180, 0.690], 'number': 37} elements[ 38] = elements[ 'Sr'] = {'symbol': 'Sr', 'name': 'strontium', 'mass': 87.62000000, 'radius': 1.9500, 'color': [0.000, 1.000, 0.000], 'number': 38} elements[ 39] = elements[ 'Y'] = {'symbol': 'Y', 'name': 'yttrium', 'mass': 88.90585000, 'radius': 1.9000, 'color': [0.580, 1.000, 1.000], 'number': 39} elements[ 40] = elements[ 'Zr'] = {'symbol': 'Zr', 'name': 'zirconium', 'mass': 91.22400000, 'radius': 1.7500, 'color': [0.580, 0.878, 0.878], 'number': 40} elements[ 41] = elements[ 'Nb'] = {'symbol': 'Nb', 'name': 'niobium', 'mass': 92.90638000, 'radius': 1.6400, 'color': [0.451, 0.761, 0.788], 'number': 41} elements[ 42] = elements[ 'Mo'] = {'symbol': 'Mo', 'name': 'molybdenum', 'mass': 95.96000000, 'radius': 1.5400, 'color': [0.329, 0.710, 0.710], 'number': 42} elements[ 43] = elements[ 'Tc'] = {'symbol': 'Tc', 'name': 'technetium', 'mass': 98.00000000, 'radius': 1.4700, 'color': [0.231, 0.620, 0.620], 'number': 43} elements[ 44] = elements[ 'Ru'] = {'symbol': 'Ru', 'name': 'ruthenium', 'mass': 101.07000000, 'radius': 1.4600, 'color': [0.141, 0.561, 0.561], 'number': 44} elements[ 45] = elements[ 'Rh'] = {'symbol': 'Rh', 'name': 'rhodium', 'mass': 102.90550000, 'radius': 1.4200, 'color': [0.039, 0.490, 0.549], 'number': 45} elements[ 46] = elements[ 'Pd'] = {'symbol': 'Pd', 'name': 'palladium', 'mass': 106.42000000, 'radius': 1.3900, 'color': [0.000, 0.412, 0.522], 'number': 46} elements[ 47] = elements[ 'Ag'] = {'symbol': 'Ag', 'name': 'silver', 'mass': 107.86820000, 'radius': 1.4500, 'color': [0.753, 0.753, 0.753], 'number': 47} elements[ 48] = elements[ 'Cd'] = {'symbol': 'Cd', 'name': 'cadmium', 'mass': 112.41100000, 'radius': 1.4400, 'color': [1.000, 0.851, 0.561], 'number': 48} elements[ 49] = elements[ 'In'] = {'symbol': 'In', 'name': 'indium', 'mass': 114.81800000, 'radius': 1.4200, 'color': [0.651, 0.459, 0.451], 'number': 49} elements[ 50] = elements[ 'Sn'] = {'symbol': 'Sn', 'name': 'tin', 'mass': 118.71000000, 'radius': 1.3900, 'color': [0.400, 0.502, 0.502], 'number': 50} elements[ 51] = elements[ 'Sb'] = {'symbol': 'Sb', 'name': 'antimony', 'mass': 121.76000000, 'radius': 1.3900, 'color': [0.620, 0.388, 0.710], 'number': 51} elements[ 52] = elements[ 'Te'] = {'symbol': 'Te', 'name': 'tellurium', 'mass': 127.60000000, 'radius': 1.3800, 'color': [0.831, 0.478, 0.000], 'number': 52} elements[ 53] = elements[ 'I'] = {'symbol': 'I', 'name': 'iodine', 'mass': 126.90470000, 'radius': 1.3900, 'color': [0.580, 0.000, 0.580], 'number': 53} elements[ 54] = elements[ 'Xe'] = {'symbol': 'Xe', 'name': 'xenon', 'mass': 131.29300000, 'radius': 1.4000, 'color': [0.259, 0.620, 0.690], 'number': 54} elements[ 55] = elements[ 'Cs'] = {'symbol': 'Cs', 'name': 'cesium', 'mass': 132.90545190, 'radius': 2.4400, 'color': [0.341, 0.090, 0.561], 'number': 55} elements[ 56] = elements[ 'Ba'] = {'symbol': 'Ba', 'name': 'barium', 'mass': 137.32700000, 'radius': 2.1500, 'color': [0.000, 0.788, 0.000], 'number': 56} elements[ 57] = elements[ 'La'] = {'symbol': 'La', 'name': 'lanthanum', 'mass': 138.90547000, 'radius': 2.0700, 'color': [0.439, 0.831, 1.000], 'number': 57} elements[ 58] = elements[ 'Ce'] = {'symbol': 'Ce', 'name': 'cerium', 'mass': 140.11600000, 'radius': 2.0400, 'color': [1.000, 1.000, 0.780], 'number': 58} elements[ 59] = elements[ 'Pr'] = {'symbol': 'Pr', 'name': 'praseodymium', 'mass': 140.90765000, 'radius': 2.0300, 'color': [0.851, 1.000, 0.780], 'number': 59} elements[ 60] = elements[ 'Nd'] = {'symbol': 'Nd', 'name': 'neodymium', 'mass': 144.24200000, 'radius': 2.0100, 'color': [0.780, 1.000, 0.780], 'number': 60} elements[ 61] = elements[ 'Pm'] = {'symbol': 'Pm', 'name': 'promethium', 'mass': 145.00000000, 'radius': 1.9900, 'color': [0.639, 1.000, 0.780], 'number': 61} elements[ 62] = elements[ 'Sm'] = {'symbol': 'Sm', 'name': 'samarium', 'mass': 150.36000000, 'radius': 1.9800, 'color': [0.561, 1.000, 0.780], 'number': 62} elements[ 63] = elements[ 'Eu'] = {'symbol': 'Eu', 'name': 'europium', 'mass': 151.96400000, 'radius': 1.9800, 'color': [0.380, 1.000, 0.780], 'number': 63} elements[ 64] = elements[ 'Gd'] = {'symbol': 'Gd', 'name': 'gadolinium', 'mass': 157.25000000, 'radius': 1.9600, 'color': [0.271, 1.000, 0.780], 'number': 64} elements[ 65] = elements[ 'Tb'] = {'symbol': 'Tb', 'name': 'terbium', 'mass': 158.92535000, 'radius': 1.9400, 'color': [0.189, 1.000, 0.780], 'number': 65} elements[ 66] = elements[ 'Dy'] = {'symbol': 'Dy', 'name': 'dysprosium', 'mass': 162.50000000, 'radius': 1.9200, 'color': [0.122, 1.000, 0.780], 'number': 66} elements[ 67] = elements[ 'Ho'] = {'symbol': 'Ho', 'name': 'holmium', 'mass': 164.93032000, 'radius': 1.9200, 'color': [0.000, 1.000, 0.612], 'number': 67} elements[ 68] = elements[ 'Er'] = {'symbol': 'Er', 'name': 'erbium', 'mass': 167.25900000, 'radius': 1.8900, 'color': [0.000, 0.902, 0.459], 'number': 68} elements[ 69] = elements[ 'Tm'] = {'symbol': 'Tm', 'name': 'thulium', 'mass': 168.93421000, 'radius': 1.9000, 'color': [0.000, 0.831, 0.322], 'number': 69} elements[ 70] = elements[ 'Yb'] = {'symbol': 'Yb', 'name': 'ytterbium', 'mass': 173.05400000, 'radius': 1.8700, 'color': [0.000, 0.749, 0.220], 'number': 70} elements[ 71] = elements[ 'Lu'] = {'symbol': 'Lu', 'name': 'lutetium', 'mass': 174.96680000, 'radius': 1.8700, 'color': [0.000, 0.671, 0.141], 'number': 71} elements[ 72] = elements[ 'Hf'] = {'symbol': 'Hf', 'name': 'hafnium', 'mass': 178.49000000, 'radius': 1.7500, 'color': [0.302, 0.761, 1.000], 'number': 72} elements[ 73] = elements[ 'Ta'] = {'symbol': 'Ta', 'name': 'tantalum', 'mass': 180.94788000, 'radius': 1.7000, 'color': [0.302, 0.651, 1.000], 'number': 73} elements[ 74] = elements[ 'W'] = {'symbol': 'W', 'name': 'tungsten', 'mass': 183.84000000, 'radius': 1.6200, 'color': [0.129, 0.580, 0.839], 'number': 74} elements[ 75] = elements[ 'Re'] = {'symbol': 'Re', 'name': 'rhenium', 'mass': 186.20700000, 'radius': 1.5100, 'color': [0.149, 0.490, 0.671], 'number': 75} elements[ 76] = elements[ 'Os'] = {'symbol': 'Os', 'name': 'osmium', 'mass': 190.23000000, 'radius': 1.4400, 'color': [0.149, 0.400, 0.588], 'number': 76} elements[ 77] = elements[ 'Ir'] = {'symbol': 'Ir', 'name': 'iridium', 'mass': 192.21700000, 'radius': 1.4100, 'color': [0.090, 0.329, 0.529], 'number': 77} elements[ 78] = elements[ 'Pt'] = {'symbol': 'Pt', 'name': 'platinum', 'mass': 195.08400000, 'radius': 1.3600, 'color': [0.816, 0.816, 0.878], 'number': 78} elements[ 79] = elements[ 'Au'] = {'symbol': 'Au', 'name': 'gold', 'mass': 196.96656900, 'radius': 1.3600, 'color': [1.000, 0.820, 0.137], 'number': 79} elements[ 80] = elements[ 'Hg'] = {'symbol': 'Hg', 'name': 'mercury', 'mass': 200.59000000, 'radius': 1.3200, 'color': [0.722, 0.722, 0.816], 'number': 80} elements[ 81] = elements[ 'Tl'] = {'symbol': 'Tl', 'name': 'thallium', 'mass': 204.38330000, 'radius': 1.4500, 'color': [0.651, 0.329, 0.302], 'number': 81} elements[ 82] = elements[ 'Pb'] = {'symbol': 'Pb', 'name': 'lead', 'mass': 207.20000000, 'radius': 1.4600, 'color': [0.341, 0.349, 0.380], 'number': 82} elements[ 83] = elements[ 'Bi'] = {'symbol': 'Bi', 'name': 'bismuth', 'mass': 208.98040000, 'radius': 1.4800, 'color': [0.620, 0.310, 0.710], 'number': 83} elements[ 84] = elements[ 'Po'] = {'symbol': 'Po', 'name': 'polonium', 'mass': 210.00000000, 'radius': 1.4000, 'color': [0.671, 0.361, 0.000], 'number': 84} elements[ 85] = elements[ 'At'] = {'symbol': 'At', 'name': 'astatine', 'mass': 210.00000000, 'radius': 1.5000, 'color': [0.459, 0.310, 0.271], 'number': 85} elements[ 86] = elements[ 'Rn'] = {'symbol': 'Rn', 'name': 'radon', 'mass': 220.00000000, 'radius': 1.5000, 'color': [0.259, 0.510, 0.588], 'number': 86} elements[ 87] = elements[ 'Fr'] = {'symbol': 'Fr', 'name': 'francium', 'mass': 223.00000000, 'radius': 2.6000, 'color': [0.259, 0.000, 0.400], 'number': 87} elements[ 88] = elements[ 'Ra'] = {'symbol': 'Ra', 'name': 'radium', 'mass': 226.00000000, 'radius': 2.2100, 'color': [0.000, 0.490, 0.000], 'number': 88} elements[ 89] = elements[ 'Ac'] = {'symbol': 'Ac', 'name': 'actinium', 'mass': 227.00000000, 'radius': 2.1500, 'color': [0.439, 0.671, 0.980], 'number': 89} elements[ 90] = elements[ 'Th'] = {'symbol': 'Th', 'name': 'thorium', 'mass': 231.03588000, 'radius': 2.0600, 'color': [0.000, 0.729, 1.000], 'number': 90} elements[ 91] = elements[ 'Pa'] = {'symbol': 'Pa', 'name': 'protactinium', 'mass': 232.03806000, 'radius': 2.0000, 'color': [0.000, 0.631, 1.000], 'number': 91} elements[ 92] = elements[ 'U'] = {'symbol': 'U', 'name': 'uranium', 'mass': 237.00000000, 'radius': 1.9600, 'color': [0.000, 0.561, 1.000], 'number': 92} elements[ 93] = elements[ 'Np'] = {'symbol': 'Np', 'name': 'neptunium', 'mass': 238.02891000, 'radius': 1.9000, 'color': [0.000, 0.502, 1.000], 'number': 93} elements[ 94] = elements[ 'Pu'] = {'symbol': 'Pu', 'name': 'plutonium', 'mass': 243.00000000, 'radius': 1.8700, 'color': [0.000, 0.420, 1.000], 'number': 94} elements[ 95] = elements[ 'Am'] = {'symbol': 'Am', 'name': 'americium', 'mass': 244.00000000, 'radius': 1.8000, 'color': [0.329, 0.361, 0.949], 'number': 95} elements[ 96] = elements[ 'Cm'] = {'symbol': 'Cm', 'name': 'curium', 'mass': 247.00000000, 'radius': 1.6900, 'color': [0.471, 0.361, 0.890], 'number': 96} elements[ 97] = elements[ 'Bk'] = {'symbol': 'Bk', 'name': 'berkelium', 'mass': 247.00000000, 'radius': 1.6600, 'color': [0.541, 0.310, 0.890], 'number': 97} elements[ 98] = elements[ 'Cf'] = {'symbol': 'Cf', 'name': 'californium', 'mass': 251.00000000, 'radius': 1.6800, 'color': [0.631, 0.212, 0.831], 'number': 98} elements[ 99] = elements[ 'Es'] = {'symbol': 'Es', 'name': 'einsteinium', 'mass': 252.00000000, 'radius': 1.6500, 'color': [0.702, 0.122, 0.831], 'number': 99} elements[100] = elements[ 'Fm'] = {'symbol': 'Fm', 'name': 'fermium', 'mass': 257.00000000, 'radius': 1.6700, 'color': [0.702, 0.122, 0.729], 'number': 100} elements[101] = elements[ 'Md'] = {'symbol': 'Md', 'name': 'mendelevium', 'mass': 258.00000000, 'radius': 1.7300, 'color': [0.702, 0.051, 0.651], 'number': 101} elements[102] = elements[ 'No'] = {'symbol': 'No', 'name': 'nobelium', 'mass': 259.00000000, 'radius': 1.7600, 'color': [0.741, 0.051, 0.529], 'number': 102} elements[103] = elements[ 'Lr'] = {'symbol': 'Lr', 'name': 'lawrencium', 'mass': 266.00000000, 'radius': 1.6100, 'color': [0.780, 0.000, 0.400], 'number': 103} elements[104] = elements[ 'Rf'] = {'symbol': 'Rf', 'name': 'rutherfordium', 'mass': 267.00000000, 'radius': 1.5700, 'color': [0.800, 0.000, 0.349], 'number': 104} elements[105] = elements[ 'Db'] = {'symbol': 'Db', 'name': 'dubnium', 'mass': 268.00000000, 'radius': 1.4900, 'color': [0.820, 0.000, 0.310], 'number': 105} elements[106] = elements[ 'Sg'] = {'symbol': 'Sg', 'name': 'seaborgium', 'mass': 269.00000000, 'radius': 1.4300, 'color': [0.851, 0.000, 0.271], 'number': 106} elements[107] = elements[ 'Bh'] = {'symbol': 'Bh', 'name': 'bohrium', 'mass': 270.00000000, 'radius': 1.4100, 'color': [0.878, 0.000, 0.220], 'number': 107} elements[108] = elements[ 'Hs'] = {'symbol': 'Hs', 'name': 'hassium', 'mass': 270.00000000, 'radius': 1.3400, 'color': [0.902, 0.000, 0.180], 'number': 108} elements[109] = elements[ 'Mt'] = {'symbol': 'Mt', 'name': 'meitnerium', 'mass': 278.00000000, 'radius': 1.2900, 'color': [0.922, 0.000, 0.149], 'number': 109} elements[110] = elements[ 'Ds'] = {'symbol': 'Ds', 'name': 'darmstadtium', 'mass': 281.00000000, 'radius': 1.2800, 'color': [0.922, 0.000, 0.149], 'number': 110} elements[111] = elements[ 'Rg'] = {'symbol': 'Rg', 'name': 'roentgenium', 'mass': 282.00000000, 'radius': 1.2100, 'color': [0.922, 0.000, 0.149], 'number': 111} elements[112] = elements[ 'Cn'] = {'symbol': 'Cn', 'name': 'copernicium', 'mass': 285.00000000, 'radius': 1.2200, 'color': [0.922, 0.000, 0.149], 'number': 112} elements[113] = elements[ 'Nh'] = {'symbol': 'Nh', 'name': 'nihonium', 'mass': 286.00000000, 'radius': 1.3600, 'color': [0.922, 0.000, 0.149], 'number': 113} elements[114] = elements[ 'Fl'] = {'symbol': 'Fl', 'name': 'flerovium', 'mass': 289.00000000, 'radius': 1.4300, 'color': [0.922, 0.000, 0.149], 'number': 114} elements[115] = elements[ 'Mc'] = {'symbol': 'Mc', 'name': 'moscovium', 'mass': 290.00000000, 'radius': 1.5800, 'color': [0.922, 0.000, 0.149], 'number': 115} elements[116] = elements[ 'Lv'] = {'symbol': 'Lv', 'name': 'livermorium', 'mass': 293.00000000, 'radius': 1.6600, 'color': [0.922, 0.000, 0.149], 'number': 116} elements[117] = elements[ 'Ts'] = {'symbol': 'Ts', 'name': 'tennessine', 'mass': 294.00000000, 'radius': 1.5600, 'color': [0.922, 0.000, 0.149], 'number': 117} elements[118] = elements[ 'Og'] = {'symbol': 'Og', 'name': 'oganesson', 'mass': 294.00000000, 'radius': 1.5700, 'color': [0.922, 0.000, 0.149], 'number': 118}