def _orthorhombic_bulk(name, x, a, covera=None): if x == 'fcc': b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif x == 'bcc': atoms = Atoms(2 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif x == 'hcp': atoms = Atoms(4 * name, cell=(a, a * sqrt(3), covera * a), scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 1.0 / 6.0, 0.5), (0, 2.0 / 3.0, 0.5)], pbc=True) elif x == 'diamond': atoms = _orthorhombic_bulk(2 * name, 'zincblende', a) elif x == 'zincblende': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0, 0.25), (0.5, 0.5, 0.5), (0, 0.5, 0.75)]) elif x == 'rocksalt': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 0.5, 0.5), (0, 0, 0.5)]) else: raise RuntimeError return atoms
def last2ads_index(atoms, species): """Return the indexes of the last n atoms in the atoms object, where n is the length of the composition of the adsorbate species. This function will work on atoms objects, where the slab was set up first, and the adsorbate was added after. Parameters ---------- atoms : ase atoms object. atoms.info must be a dictionary containing the key 'key_value_pairs', which is expected to contain CATMAP standard adsorbate structure key value pairs. See the ase db to catmap module in catmap. the key value pair 'species' must be the chemical formula of the adsorbate. species : str chemical formula of the adsorbate. """ n_ads = len(string2symbols(species)) natoms = len(atoms) ads_atoms = list(range(natoms - n_ads, natoms)) composition = string2symbols(species) for a in ads_atoms: if atoms[a].symbol not in composition: raise AssertionError("last index adsorbate identification failed.") warnings.warn("Adsorbate identified by last index.") return ads_atoms
def valid_pair(row): ads_a = row['ads_a'] ads_b = row['ads_b'] gas = row['comp_g'] atoms_a = row['atoms_a'] atoms_b = row['atoms_b'] #a must be shorter than b, no duplicates if len(atoms_a) >= len(atoms_b): return False if ads_a == 's': if gas == ads_b: return True else: return False else: #If first element (binding element) equal, may be good if row['site_a'] != row['site_b']: return False if ads_a[0] == ads_b[0]: comp_a = Counter(string2symbols(ads_a)) comp_b = Counter(string2symbols(ads_b)) diff = comp_b - comp_a dcomp = list(diff.elements()) if len(dcomp) == 1 and gas == dcomp[0]: return True else: return False else: return False
def check(key_value_pairs): for key, value in key_value_pairs.items(): if not word.match(key) or key in reserved_keys: raise ValueError('Bad key: {}'.format(key)) try: string2symbols(key) except ValueError: pass else: warnings.warn( 'It is best not to use keys ({0}) that are also a ' 'chemical formula. If you do a "db.select({0!r})",' 'you will not find rows with your key. Instead, you wil get ' 'rows containing the atoms in the formula!'.format(key)) if not isinstance(value, (numbers.Real, basestring)): raise ValueError('Bad value for {!r}: {}'.format(key, value)) if isinstance(value, basestring): for t in [int, float]: if str_represents(value, t): raise ValueError( 'Value ' + value + ' is put in as string ' + 'but can be interpreted as ' + '{}! Please convert '.format(t.__name__) + 'to {} using '.format(t.__name__) + '{}(value) before '.format(t.__name__) + 'writing to the database OR change ' + 'to a different string.')
def check(key_value_pairs): for key, value in key_value_pairs.items(): if not word.match(key) or key in reserved_keys: raise ValueError('Bad key: {}'.format(key)) try: string2symbols(key) except ValueError: pass else: warnings.warn( 'It is best not to use keys ({0}) that are also a ' 'chemical formula. If you do a "db.select({0!r})",' 'you will not find rows with your key. Instead, you wil get ' 'rows containing the atoms in the formula!'.format(key)) if not isinstance(value, (numbers.Real, basestring, np.bool_)): raise ValueError('Bad value for {!r}: {}'.format(key, value)) if isinstance(value, basestring): for t in [int, float]: if str_represents(value, t): raise ValueError('Value ' + value + ' is put in as string ' + 'but can be interpreted as ' + '{}! Please convert '.format(t.__name__) + 'to {} using '.format(t.__name__) + '{}(value) before '.format(t.__name__) + 'writing to the database OR change ' + 'to a different string.')
def _orthorhombic_bulk(name, crystalstructure, a, covera=None, u=None): if crystalstructure == 'fcc': b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif crystalstructure == 'bcc': atoms = Atoms(2 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif crystalstructure == 'hcp': atoms = Atoms(4 * name, cell=(a, a * sqrt(3), covera * a), scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 1 / 6, 0.5), (0, 2 / 3, 0.5)], pbc=True) elif crystalstructure == 'diamond': atoms = _orthorhombic_bulk(2 * name, 'zincblende', a) elif crystalstructure == 'zincblende': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0, 0.25), (0.5, 0.5, 0.5), (0, 0.5, 0.75)]) elif crystalstructure == 'rocksalt': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 0.5, 0.5), (0, 0, 0.5)]) elif crystalstructure == 'cesiumchloride': atoms = Atoms(name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif crystalstructure == 'wurtzite': u = u or 0.25 + 1 / 3 / covera**2 atoms = Atoms(4 * name, cell=(a, a * 3**0.5, covera * a), scaled_positions=[(0, 0, 0), (0, 1 / 3, 0.5 - u), (0, 1 / 3, 0.5), (0, 0, 1 - u), (0.5, 0.5, 0), (0.5, 5 / 6, 0.5 - u), (0.5, 5 / 6, 0.5), (0.5, 0.5, 1 - u)], pbc=True) else: raise RuntimeError return atoms
def strain(self, atoms=None): """Return a fingerprint with the espected strain of the site atoms and the termination atoms. Parameters ---------- atoms : object """ if atoms is None: return ['strain_site', 'strain_term'] else: if ('key_value_pairs' in atoms.info and 'term' in atoms.info['key_value_pairs']): term = atoms.info['key_value_pairs']['term'] term_numbers = [ atomic_numbers[s] for s in string2symbols(term) ] elif 'termination_atoms' in atoms.subsets: term = atoms.subsets['termination_atoms'] term_numbers = atoms.numbers[term] else: raise NotImplementedError("strain fingerprint.") if ('key_value_pairs' in atoms.info and 'bulk' in atoms.info['key_value_pairs']): bulk = atoms.info['key_value_pairs']['bulk'] bulk_numbers = [ atomic_numbers[s] for s in string2symbols(bulk) ] elif 'bulk_atoms' in atoms.subsets: bulk = atoms.subsets['bulk_atoms'] bulk_numbers = atoms.numbers[bulk] else: raise NotImplementedError("strain fingerprint.") site = atoms.subsets['site_atoms'] site_numbers = atoms.numbers[site] rbulk = [] rterm = [] rsite = [] for b in bulk_numbers: rbulk.append(get_radius(b)) for t in term_numbers: rterm.append(get_radius(t)) for z in site_numbers: rsite.append(get_radius(z)) av_term = np.average(rterm) av_bulk = np.average(rbulk) av_site = np.average(rsite) strain_site = (av_site - av_bulk) / av_bulk strain_term = (av_term - av_bulk) / av_bulk return [strain_site, strain_term]
def _orthorhombic_bulk(name, crystalstructure, a, covera=None, u=None): if crystalstructure == 'fcc': b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif crystalstructure == 'bcc': atoms = Atoms(2 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif crystalstructure == 'hcp': atoms = Atoms(4 * name, cell=(a, a * sqrt(3), covera * a), scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 1 / 6, 0.5), (0, 2 / 3, 0.5)], pbc=True) elif crystalstructure == 'diamond': atoms = _orthorhombic_bulk(2 * name, 'zincblende', a) elif crystalstructure == 'zincblende': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0, 0.25), (0.5, 0.5, 0.5), (0, 0.5, 0.75)]) elif crystalstructure == 'rocksalt': s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 0.5, 0.5), (0, 0, 0.5)]) elif crystalstructure == 'cesiumchloride': atoms = Atoms(name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif crystalstructure == 'wurtzite': u = u or 0.25 + 1 / 3 / covera**2 atoms = Atoms(4 * name, cell=(a, a * 3**0.5, covera * a), scaled_positions = [(0, 0, 0), (0, 1 / 3, 0.5 - u), (0, 1 / 3, 0.5), (0, 0, 1 - u), (0.5, 0.5, 0), (0.5, 5 / 6, 0.5 - u), (0.5, 5 / 6, 0.5), (0.5, 0.5, 1 - u)], pbc=True) else: raise RuntimeError return atoms
def gen222(name=None, A='Sr', B='Mn', O='O', latticeconstant=3.9, mag_order='FM', mag_atom=None, m=5, sort=True): if name is not None: symbols = string2symbols(name) A, B, O, _, _ = symbols atoms = PerovskiteCubic([A, B, O], latticeconstant=latticeconstant) atoms = atoms.repeat([2, 2, 2]) if sort: my_write_vasp('UCPOSCAR', atoms, vasp5=True, sort=True) atoms = read_vasp('UCPOSCAR') spin_dn = { 'FM': [], 'A': [0, 1, 4, 5], 'C': [0, 2, 5, 7], 'G': [0, 3, 5, 6] } if mag_order != 'PM': mag = np.ones(8) mag[np.array(spin_dn[mag_order], int)] = -1.0 if mag_atom is None: atoms = set_element_mag(atoms, B, mag * m) else: atoms = set_element_mag(atoms, mag_atom, mag * m) return atoms
def __getitem__(self, name): d = self.data[name] # the index of label in labels less one # (compound is already as key in d) a = d[self.labels.index("aexp") - 1] if name in ["Cr2CoGa", "Mn2CoAl", "Mn2CoGe", "Fe2CoSi"]: # http://en.wikipedia.org/wiki/Space_group sg = 216 else: sg = 225 symbols = string2symbols(name) symbols.pop(0) b = crystal( symbols=symbols, basis=[(1.0 / 4, 1.0 / 4, 1.0 / 4), (0.0, 0.0, 0.0), (1.0 / 2, 1.0 / 2, 1.0 / 2)], spacegroup=sg, cellpar=[a, a, a, 90, 90, 90], primitive_cell=True, ) # set average moments on all atoms (add + 2.0) magmom = d[self.labels.index("mexp") - 1] + 2.0 m = [magmom / len(b)] * len(b) # break spin symmetry between atoms no. 1 and 2 m[1] = m[1] + m[2] m[2] = -m[2] b.set_initial_magnetic_moments(m) if 0: from ase.visualize import view view(b) return b
def layers2ads_index(atoms, species): """ Returns the indexes of atoms in layers exceeding the number of layers stored in the key value pair 'layers'. Parameters ---------- atoms : ase atoms object. atoms.info must be a dictionary containing the key 'key_value_pairs', which is expected to contain CatMAP standard adsorbate structure key value pairs. See the ase db to catmap module in catmap. the key value pair 'species' must be the chemical formula of the adsorbate and 'layers' must be an integer. species : str chemical formula of the adsorbate. """ lz, li = auto_layers(atoms) layers = int(atoms.info['key_value_pairs']['layers']) ads_atoms = [a.index for a in atoms if li[a.index] > layers - 1] natoms = len(atoms) composition = string2symbols(species) n_ads = len(composition) ads_atoms = list(range(natoms - n_ads, natoms)) if len(ads_atoms) != len(composition): raise AssertionError("ads atoms identification by layers failed.") return ads_atoms
def dia_100_2x1(sym, a0): sym = string2symbols(sym) if len(sym) == 1: a = Diamond(sym[0], size = [2*nx, nx, nz], latticeconstant = a0, directions=[ [1,-1,0], [1,1,0], [0,0,1] ] ) else: a = B3(sym, size = [2*nx, nx, nz], latticeconstant = a0, directions=[ [1,-1,0], [1,1,0], [0,0,1] ] ) sx, sy, sz = a.get_cell().diagonal() a.translate([sx/(8*nx), sy/(8*nx), sz/(8*nz)]) bulk = a.copy() for i in a: if i.z < sz/(4*nz) or i.z > sz-sz/(4*nz): if i.x < sx/2: i.x = i.x+0.5 else: i.x = i.x-0.5 return bulk, a
def get_parameters(file, number=2): file = open(file) text = file.read() file.close() # Find elements s = -1 for i in range(number): s = text.find('Optimization', s + 1) if s < 0: raise ValueError("No results in file (keyword Optimization missing in file)") e = text.find('\n', s) errfunc = float(text[s:e].split()[6]) result = {} s = e + 1 e = text.find('Fitting values', s) - 4 for line in text[s:e].split('\n'): words = line.strip().split() if words[1] == 'parameters': elements = tuple(string2symbols(words[0])) result[elements] = [] else: result[elements].append(float(words[1])) return result, errfunc
def calc_formation_energy(symbl, ene, ref_dict, surf_name='surf'): """ calculate the formation energy in terms of the symbol, the energy and the reference energy dictory <symbl> can CH2, CH2_s etc. in ref_dict, the pure surface is denoted as 'slab' """ from ase.atoms import string2symbols E0 = ene if '_s' in symbl: name, site = symbl.split('_') #split key into name/site E0 -= ref_dict[surf_name] else: name = symbl #remove - from transition-states formula = name.replace('-', '') #get the composition as a list of atomic species composition = string2symbols(formula) #for each atomic species, subtract off the reference energy for atom in composition: E0 -= ref_dict[atom] #round to 3 decimals since this is the accuracy of DFT E0 = round(E0, 3) return E0
def build_system(self, name): try: # Known molecule or atom? atoms = molecule(name) if len(atoms) == 2 and self.bond_length is not None: atoms.set_distance(0, 1, self.bond_length) except NotImplementedError: symbols = string2symbols(name) if len(symbols) == 1: magmom = ground_state_magnetic_moments[atomic_numbers[ symbols[0]]] atoms = Atoms(name, magmoms=[magmom]) elif len(symbols) == 2: # Dimer if self.bond_length is None: b = (covalent_radii[atomic_numbers[symbols[0]]] + covalent_radii[atomic_numbers[symbols[1]]]) else: b = self.bond_length atoms = Atoms(name, positions=[(0, 0, 0), (b, 0, 0)]) else: raise ValueError('Unknown molecule: ' + name) if self.unit_cell is None: atoms.center(vacuum=self.vacuum) else: atoms.cell = self.unit_cell atoms.center() return atoms
def build_system(self, name): try: # Known molecule or atom? atoms = molecule(name) if len(atoms) == 2 and self.bond_length is not None: atoms.set_distance(0, 1, self.bond_length) except NotImplementedError: symbols = string2symbols(name) if len(symbols) == 1: Z = atomic_numbers[symbols[0]] magmom = ground_state_magnetic_moments[Z] atoms = Atoms(name, magmoms=[magmom]) elif len(symbols) == 2: # Dimer if self.bond_length is None: b = (covalent_radii[atomic_numbers[symbols[0]]] + covalent_radii[atomic_numbers[symbols[1]]]) else: b = self.bond_length atoms = Atoms(name, positions=[(0, 0, 0), (b, 0, 0)]) else: raise ValueError('Unknown molecule: ' + name) if self.unit_cell is None: atoms.center(vacuum=self.vacuum) else: atoms.cell = self.unit_cell atoms.center() return atoms
def bulk(self, atoms=None): """Return a fingerprint vector with propeties averaged over the bulk atoms. Parameters ---------- atoms : object """ labels = make_labels(self.slab_params, '', '_bulk') labels.append('ground_state_magmom_bulk') if atoms is None: return labels else: if ('key_value_pairs' in atoms.info and 'bulk' in atoms.info['key_value_pairs']): bulk = atoms.info['key_value_pairs']['bulk'] numbers = [atomic_numbers[s] for s in string2symbols(bulk)] elif 'bulk_atoms' in atoms.subsets: bulk = atoms.subsets['bulk_atoms'] numbers = atoms.numbers[bulk] else: raise NotImplementedError("bulk fingerprint.") dat = list_mendeleev_params(numbers, params=self.slab_params) result = list(np.nanmean(dat, axis=0)) result += [np.nanmean([gs_magmom[z] for z in numbers])] check_labels(labels, result, atoms) return result
def get_atomic_stoichiometry(references): """ Given a list of references (tuples of (symbol, molecule)) return stoichiometry matrix that connects atomic symbols to its molecular references. """ n = len(references) stoichiometry = np.ndarray((n, n), float) stoichiometry[:] = 0. key_index = {} for i, (key, species) in enumerate(references): # in case species uses a suffix like _gas species = species.split('_')[0] key_index[key] = i composition = string2symbols(species) for j, symbol in enumerate(composition): if symbol == key: stoichiometry[i, i] += 1 else: stoichiometry[i, key_index[symbol]] -= 1 for i in range(n): stoichiometry[i, i] = 1. / stoichiometry[i, i] for i in range(n): for j in range(n): if i != j: stoichiometry[i, j] *= stoichiometry[j, j] return stoichiometry.tolist()
def construct_reference_system( symbols, candidates=['H2', 'H2O', 'NH3', 'CH4', 'CO', 'SH2', 'HCl', 'N2', 'O2']): """ Take a list of symbols and construct gas phase references system, when possible avoiding O2. Candidates can be rearranged, where earlier candidates get higher preference than later candidates """ # assume symbols sorted by atomic number references = {} added_symbols = [] for symbol in symbols: added_symbols.append(symbol) for candidate in candidates: symbols = string2symbols(candidate) if set(added_symbols) == set(list(references.keys()) + symbols): references[symbol] = candidate break else: raise UserWarning( "No candidate satisfied {symbol}. Add more candidates".format( **locals())) return sorted(references.items(), key=lambda _x: ase.data.atomic_numbers[_x[0]])
def molecules2symbols(molecules, add_hydrogen=True): """ Take a list of molecules and return just a list of atomic symbols, possibly adding hydrogen """ symbols = sorted(list( set( string2symbols(''.join( map(lambda _x: ''.join(string2symbols(_x)), molecules))))), key=lambda _y: ase.data.atomic_numbers[_y]) if add_hydrogen and not 'H' in symbols: symbols.insert(0, 'H') return symbols
def get_stoichiometry_factors(adsorbates, references): """ Take a list of adsorabtes and a corresponding reference system and return a list of dictionaries encoding the stoichiometry factors converting between adsorbates and reference molecules. """ stoichiometry = get_atomic_stoichiometry(references) stoichiometry_factors = {} for adsorbate in adsorbates: for symbol in string2symbols(adsorbate): symbol_index = list(map(lambda _x: _x[0], references)).index(symbol) for (factor, (ref_symbol, ref_molecule)) in zip(stoichiometry[symbol_index], references): stoichiometry_factors.setdefault( adsorbate, {})[ref_molecule] = stoichiometry_factors.setdefault( adsorbate, {}).get(ref_molecule, 0) + factor nonzero_factors = {} for key, value in stoichiometry_factors[adsorbate].items(): if not np.isclose(value, 0.): nonzero_factors[key] = value stoichiometry_factors[adsorbate] = nonzero_factors return stoichiometry_factors
def get_formation_energies(energy_dict, ref_dict, surf_name='111'): """ calculate the formation energy based on the energy data given in energy_dict using the reference energies given in ref_dict """ from ase.atoms import string2symbols formation_energies = {} for key in energy_dict.keys(): #iterate through keys E0 = energy_dict[key] #raw energy name, site = key.split('_') #split key into name/site if 'slab' not in name: #do not include empty site energy (0) if site == surf_name: E0 -= ref_dict[site] #subtract slab energy if adsorbed #remove - from transition-states formula = name.replace('-', '') #get the composition as a list of atomic species composition = string2symbols(formula) #for each atomic species, subtract off the reference energy for atom in composition: E0 -= ref_dict[atom] #round to 3 decimals since this is the accuracy of DFT E0 = round(E0, 3) formation_energies[key] = E0 return formation_energies
def gen_primitive(name=None,A=None,B=None,O=None, latticeconstant=3.9, mag_order='FM', m=5): """ generate primitive cell with magnetic order. Parameters: --------------- name: string ABO3, eg. BiFeO3, CsPbF3 """ if name is not None: symbols=string2symbols(name) A, B, O, _, _ = symbols atoms = PerovskiteCubic([A, B, O], latticeconstant=latticeconstant) direction_dict = { 'A': ([1, 0, 0], [0, 1, 0], [0, 0, 2]), 'C': ([1, -1, 0], [1, 1, 0], [0, 0, 1]), 'G': ([0, 1, 1], [1, 0, 1], [1, 1, 0]), 'FM': np.eye(3), } size_dict = {'A': (1, 1, 2), 'C': (1, 1, 1), 'G': (1, 1, 1)} A, B, O = atoms.get_chemical_symbols()[0:3] if mag_order == 'PM': atoms = atoms elif mag_order == 'FM': atoms = atoms atoms = set_element_mag(atoms, B, [m]) else: atoms.translate([0.045] * 3) atoms = normalize(atoms) atoms = make_supercell(atoms, direction_dict[mag_order]) atoms.translate([-0.045] * 3) atoms = set_element_mag(atoms, B, [m, -m]) return atoms
def formula2ads_index(atoms, species): """Return the indexes of atoms, which have symbols matching the chemical formula of the adsorbate. This function will not work for adsorbates containing the same elements as the slab. Parameters ---------- atoms : ase atoms object. atoms.info must be a dictionary containing the key 'key_value_pairs', which is expected to contain CatMAP standard adsorbate structure key value pairs. See the ase db to catmap module in catmap. the key value pair 'species' must be the chemical formula of the adsorbate. species : str chemical formula of the adsorbate. """ try: composition = string2symbols(species) except ValueError: print(species) raise ads_atoms = [a.index for a in atoms if a.symbol in composition] if len(ads_atoms) != len(composition): raise AssertionError("ads atoms identification by formula failed.") return ads_atoms
def do_calculations(self, formulas): """Perform calculation on molecules, write results to .gpw files.""" atoms = {} for formula in formulas: for symbol in string2symbols(formula.split('_')[0]): atoms[symbol] = None formulas = formulas + atoms.keys() for formula in formulas: if path.isfile(formula + '.gpw'): continue barrier() open(formula + '.gpw', 'w') s = molecule(formula) s.center(vacuum=self.vacuum) cell = s.get_cell() h = self.h s.set_cell((cell / (4 * h)).round() * 4 * h) s.center() calc = GPAW(h=h, xc=self.xc, eigensolver=self.eigensolver, setups=self.setups, basis=self.basis, fixmom=True, txt=formula + '.txt') if len(s) == 1: calc.set(hund=True) s.set_calculator(calc) if formula == 'BeH': calc.initialize(s) calc.nuclei[0].f_si = [(1, 0, 0.5, 0, 0), (0.5, 0, 0, 0, 0)] if formula in ['NO', 'ClO', 'CH']: s.positions[:, 1] += h * 1.5 try: energy = s.get_potential_energy() except (RuntimeError, ConvergenceError): if rank == 0: print >> sys.stderr, 'Error in', formula traceback.print_exc(file=sys.stderr) else: print >> self.txt, formula, repr(energy) self.txt.flush() calc.write(formula) if formula in diatomic and self.calculate_dimer_bond_lengths: traj = PickleTrajectory(formula + '.traj', 'w') d = diatomic[formula][1] for x in range(-2, 3): s.set_distance(0, 1, d * (1.0 + x * 0.02)) traj.write(s)
def test_ddb(name): symbols = string2symbols(name) masses = [atomic_masses[atomic_numbers[s]] for s in symbols] # split ddb file dirname = "%s_PM_pjte" % name fname = os.path.join(dirname, 'abinito_DS2_DDB') reader = ddb_reader(fname) reader.gen_pjte_ddbs() ifcmat1d = get_mat1d(dirname, masses, term='TOT') #ifcmat1d=asr_1d(ifcmat1d) #print ifcmat1d eigvals, eigvecs = eigh(ifcmat1d, ) s = np.sign(eigvals) #print eigvals #print "Phonon Freq (Ha):" #print s*np.sqrt(s*eigvals)/Ha print("Phonon Freq (cm-1):") print(s * np.sqrt(s * eigvals) * 19474.63 / Ha) #print np.dot(np.dot(v,ifcmat1d),v) print("--Eigen vector:--") v = eigvecs[:, 0] ifcmat1d_fr = get_mat1d(dirname, masses, term='FR') ifcmat1d_nfr = get_mat1d(dirname, masses, term='NFR') ifcmat1d_ew = get_mat1d(dirname, masses, term='EW') print(ifcmat1d_ew) print("self IFC") print([ifcmat1d[i,i] for i in range(5)]) #func=lambda mat: np.sign(v)* np.sqrt(np.sign(v)*) def func(mat): eigv = np.dot(np.dot(v, mat), v) s = np.sign(eigv) return s * np.sqrt(s * eigv) * 19474.63 / Ha #print "w:" print("Total:", func(ifcmat1d)) print("Frozen:", func(ifcmat1d_fr)) print("Non-Frozen:", func(ifcmat1d_nfr)) print("Ewald:", func(ifcmat1d_ew)) for i in range(5): print("-- %s --"%symbols[i]) v=[0,0,0,0,0] v[i]=1.0 #func=lambda mat: np.sign(v)* np.sqrt(np.sign(v)*) def func(mat): eigv = np.dot(np.dot(v, mat), v) s = np.sign(eigv) return s * np.sqrt(s * eigv) * 19474.63 / Ha print("Total:", func(ifcmat1d)) print("Frozen:", func(ifcmat1d_fr)) print("Non-Frozen:", func(ifcmat1d_nfr)) print("Ewald:", func(ifcmat1d_ew))
def get_composition(species_string): composition = {} try: symbs = string2symbols(species_string.replace('-', '')) for a in set(symbs): composition[a] = symbs.count(a) except ValueError: composition = None return composition
def get_composition(species_string): composition = {} try: symbs = string2symbols(species_string.replace('-','')) for a in set(symbs): composition[a] = symbs.count(a) except ValueError: composition = None return composition
def solid_Lange(symbols,T): """Extract stable solid and their energies from database and calculate the specific Gibbs formation energies when T != 298.15 K. symbols: str Extract only those molecules that contain the chemical elements given by the symbols string (plus water and H+). Data from: experimental literatures: D. D. Wagman, et al., The NBS Tables of Chemical Thermodynamic Properties, in J. Phys. Chem. Ref. Data, 11: 2, 1982; M. W. Chase, et al., JANAF Thermochemical Tables, 3rd ed., American Chemical Society and the American Institute of Physics, 1986 (supplements to JANAF appear in J. Phys. Chem. Ref. Data); Thermodynamic Research Center, TRC Thermodynamic Tables, Texas A&M University, College Station, Texas; I. Barin and O. Knacke, Thermochemical Properties of Inorganic Substances, Springer-Verlag, Berlin, 1973; Returns list of (name, energy) tuples. """ if isinstance(symbols, basestring): symbols = set(string2symbols(symbols)) conn = sqlite3.connect('apps/pourbaix/data/data_ase/lange_handbook.db') cur = conn.cursor() cur.execute("SELECT * FROM lange_solids") rows = cur.fetchall() if len(_solids)==0: for row in rows: formula = row[0] energy = row[4] heat_cap_std = row[6] entropy_f_std = row[7] name = formula + '(s)' count, charge, aq, s = parse_formula(name) if energy != "NULL": if T == 298.15: energy = float(energy) * 0.010364 #convert from kJ/mol to eV _solids.append((name, count, s, energy)) elif T != 298.15 and entropy_f_std != "NULL" and heat_cap_std != "NULL" : import math #energy unit is eV energy = (float(energy) - (T - 298.15)* float(entropy_f_std) + float(heat_cap_std)/1000*(T-298.15) - 2.303 * T* float(heat_cap_std)/1000*math.log10(T/298.15)) *0.010364 _solids.append((name, count, s, energy)) conn.close() references_solid = [] for name, count, s, energy in _solids: for symbol in count: if symbol not in 'HO' and symbol not in symbols: break else: references_solid.append((name, energy)) return references_solid
def get_atomtypes_from_formula(formula): """Return atom types from chemical formula (optionally prepended with and underscore). """ from ase.atoms import string2symbols symbols = string2symbols(formula.split('_')[0]) atomtypes = [symbols[0]] for s in symbols[1:]: if s != atomtypes[-1]: atomtypes.append(s) return atomtypes
def slab_positions2ads_index(atoms, slab, species): """Return the indexes of adsorbate atoms identified by comparing positions to a reference slab structure. Parameters ---------- atoms : object """ composition = string2symbols(species) ads_atoms = [] for symbol in composition: if (composition.count(symbol) == atoms.get_chemical_symbols().count( symbol)): ads_atoms += [ atom.index for atom in atoms if atom.symbol == symbol ] ua_ads, uc_ads = np.unique(ads_atoms, return_counts=True) ua_comp, uc_comp = np.unique(composition, return_counts=True) if ua_ads == ua_comp and uc_ads == uc_comp: return ads_atoms p_a = atoms.get_positions() p_r = slab.get_positions() for s in composition: if s in np.array(atoms.get_chemical_symbols())[ads_atoms]: continue symbol_count = composition.count(s) index_a = np.where(np.array(atoms.get_chemical_symbols()) == s)[0] index_r = np.where(np.array(slab.get_chemical_symbols()) == s)[0] _, dist = get_distances(p_a[index_a, :], p2=p_r[index_r, :], cell=atoms.cell, pbc=True) # Assume all slab atoms are closest to their reference counterpart. deviations = np.min(dist, axis=1) # Sort deviations. ascending = np.argsort(deviations) # The highest deviations are assumed to be new atoms. ads_atoms += list(index_a[ascending[-symbol_count:]]) # Final check. ua_ads, uc_ads = np.unique(np.array( atoms.get_chemical_symbols())[ads_atoms].sort(), return_counts=True) ua_comp, uc_comp = np.unique(composition.sort(), return_counts=True) if ua_ads != ua_comp: msg = str(ua_ads) + " != " + str(ua_comp) raise AssertionError(msg) elif uc_ads != uc_comp: msg = str(uc_ads) + " != " + str(uc_comp) raise AssertionError(msg) return ads_atoms
def build_molecule(args): try: # Known molecule or atom? atoms = molecule(args.name) except NotImplementedError: symbols = string2symbols(args.name) if len(symbols) == 1: Z = atomic_numbers[symbols[0]] magmom = ground_state_magnetic_moments[Z] atoms = Atoms(args.name, magmoms=[magmom]) elif len(symbols) == 2: # Dimer if args.bond_length is None: b = (covalent_radii[atomic_numbers[symbols[0]]] + covalent_radii[atomic_numbers[symbols[1]]]) else: b = args.bond_length atoms = Atoms(args.name, positions=[(0, 0, 0), (b, 0, 0)]) else: raise ValueError('Unknown molecule: ' + args.name) else: if len(atoms) == 2 and args.bond_length is not None: atoms.set_distance(0, 1, args.bond_length) if args.unit_cell is None: if args.vacuum: atoms.center(vacuum=args.vacuum) else: atoms.center(about=[0, 0, 0]) else: a = [float(x) for x in args.unit_cell.split(',')] if len(a) == 1: cell = [a[0], a[0], a[0]] elif len(a) == 3: cell = a else: a, b, c, alpha, beta, gamma = a degree = np.pi / 180.0 cosa = np.cos(alpha * degree) cosb = np.cos(beta * degree) sinb = np.sin(beta * degree) cosg = np.cos(gamma * degree) sing = np.sin(gamma * degree) cell = [[a, 0, 0], [b * cosg, b * sing, 0], [c * cosb, c * (cosa - cosb * cosg) / sing, c * np.sqrt( sinb**2 - ((cosa - cosb * cosg) / sing)**2)]] atoms.cell = cell atoms.center() atoms.pbc = args.periodic return atoms
def parse_formula(formula): aq = formula.endswith('(aq)') if aq: formula = formula[:-4] charge = formula.count('+') - formula.count('-') if charge: formula = formula.rstrip('+-') count = {} for symbol in string2symbols(formula): count[symbol] = count.get(symbol, 0) + 1 return count, charge, aq
def term(self, atoms=None): """ Returns a fingerprint vector with propeties of the element name saved in the atoms.info['key_value_pairs']['term'] """ labels = ['atomic_number_term', 'atomic_volume_term', 'boiling_point_term', 'density_term', 'dipole_polarizability_term', 'electron_affinity_term', 'group_id_term', 'lattice_constant_term', 'melting_point_term', 'period_term', 'vdw_radius_term', 'covalent_radius_cordero_term', 'en_allen_term', 'atomic_weight_term', 'atomic_radius_term', 'heat_of_formation_term', 'dft_bulk_modulus_term', 'dft_rhodensity_term', 'dbcenter_term', 'dbfilling_term', 'dbwidth_term', 'dbskew_term', 'dbkurtosis_term', 'oxi_min_term', 'oxi_med_term', 'oxi_max_term', 'block_term', 'ne_outer_term', 'ne_s_term', 'ne_p_term', 'ne_d_term', 'ne_f_term', 'ionenergy_term', 'ground_state_magmom_term'] if atoms is None: return labels else: if ('key_value_pairs' in atoms.info and 'term' in atoms.info['key_value_pairs']): term = atoms.info['key_value_pairs']['term'] numbers = [atomic_numbers[s] for s in string2symbols(term)] elif 'termination_atoms' in atoms.subsets: term = atoms.subsets['termination_atoms'] numbers = atoms.numbers[term] else: raise NotImplementedError("termination fingerprint.") dat = list_mendeleev_params(numbers, params=self.slab_params) result = list(np.nanmean(dat, axis=0)) result += [np.nanmean([gs_magmom[z] for z in numbers])] check_length(labels, result, atoms) return result
def add_ads(surf, facet, ads, site, fixed_line=True): """ Add ads (string) to surf. Bonding atom is assumed to be the first in the ads string. e.g. CO means binding through C, OC means binding through O. if fixed_line == True: add fixed_line constraint to binding atom. """ ads_atoms = read('%s/%s.traj' % (ads_prototype_dir, ads)) bonding_atoms = [ atom for atom in ads_atoms if atom.symbol == string2symbols(ads)[0] ] assert len(bonding_atoms) == 1, "" bonding_atom = bonding_atoms[0] bonding_atom_ind = bonding_atoms[0].index + len(surf) #figure out bonding atom position based n facet, site# try: #use ase builtin method if possible add_adsorbate(surf, 'X', bond_lengths[site], site) bonding_atom_pos = surf[-1].position del surf[-1] except TypeError: #find top layer top_z = sorted(set([atom.z for atom in surf]))[-1] #find first atom in top layer top_atom_inds = [atom.index for atom in surf if atom.z == top_z] top_atom = surf[top_atom_inds.pop(np.argmin( top_atom_inds))] #surface atom in top layer w/ lowest index top_atom2 = surf[top_atom_inds[np.argmin( surf.get_distances(top_atom.index, top_atom_inds))]] #1st NN to top_atom if facet == '211' and site == 'ontop': bonding_atom_pos = top_atom.position + np.array( [0, 0, bond_lengths[site]]) elif facet == '211' and site == 'bridge': bonding_atom_pos = (top_atom.position + top_atom2.position) / 2. + np.array( [0, 0, bond_lengths[site]]) elif facet == '10m10' and site == 'bridge': bonding_atom_pos = (top_atom.position + top_atom2.position) / 2. + np.array( [0, 0, bond_lengths[site]]) else: raise Exception( "Cannot add adsorbate to %s-%s (not in ase.build.surface.add_adsorbate or custom definitions)" % (facet - site)) surf += ads_atoms delta_vec = bonding_atom_pos - surf[bonding_atom_ind].position for i in range(len(surf) - len(ads_atoms), len(surf)): surf[i].position += delta_vec if fixed_line: surf.constraints.append(FixedLine(bonding_atom_ind, [0, 0, 1])) return surf
def get_composition(species_string): composition = {} # clean up transition states and electrochem species_string = species_string.replace('-','') species_string = species_string.replace('pe','H') species_string = species_string.replace('&','') try: symbs = string2symbols(species_string) for a in set(symbs): composition[a] = symbs.count(a) except ValueError: composition = None return composition
def _orthorhombic_bulk(name, x, a, covera=None): if x == "fcc": b = a / sqrt(2) atoms = Atoms(2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif x == "bcc": atoms = Atoms(2 * name, cell=(a, a, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)]) elif x == "hcp": atoms = Atoms( 4 * name, cell=(a, a * sqrt(3), covera * a), scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 1.0 / 6.0, 0.5), (0, 2.0 / 3.0, 0.5)], pbc=True, ) elif x == "diamond": atoms = _orthorhombic_bulk(2 * name, "zincblende", a) elif x == "zincblende": s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms( 2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0, 0.25), (0.5, 0.5, 0.5), (0, 0.5, 0.75)], ) elif x == "rocksalt": s1, s2 = string2symbols(name) b = a / sqrt(2) atoms = Atoms( 2 * name, cell=(b, b, a), pbc=True, scaled_positions=[(0, 0, 0), (0.5, 0.5, 0), (0.5, 0.5, 0.5), (0, 0, 0.5)], ) else: raise RuntimeError return atoms
def atomization_energies(E): """Write given atomization energies to file atomization_energies.csv.""" Ea = {} fd = open('atomization_energies.csv', 'w') for formula in sorted(molecules): ea = -E[formula] for a in string2symbols(data[formula]['symbols']): ea += E[a] eavasp = atomization_vasp[formula][1] * kcal / mol Ea[formula] = (ea, eavasp) name = latex(data[formula]['name']) fd.write('`%s`, %.3f, %.3f, %+.3f\n' % (name[1:-1], ea, eavasp, ea - eavasp)) return Ea
def dia_111_pandey(sym, a0, nx=nx, ny=nx, nz=nz): """2x1 Pandey reconstructed (111) surface.""" sym = string2symbols(sym) if len(sym) == 1: a = Diamond(sym[0], size = [nx, ny, nz], latticeconstant = a0, directions=[ [1,-1,0], [1,1,-2], [1,1,1] ] ) else: a = B3(sym, size = [nx, ny, nz], latticeconstant = a0, directions=[ [1,-1,0], [1,1,-2], [1,1,1] ] ) sx, sy, sz = a.get_cell().diagonal() a.translate([sx/(12*nx), sy/(4*ny), sz/(6*nz)]) a.set_scaled_positions(a.get_scaled_positions()%1.0) bulk = a.copy() bondlen = a0*sqrt(3)/4 x, y, z = a.positions.T mask = np.abs(z-z.max()) < 0.1*a0 top1, top2 = np.arange(len(a))[mask].reshape(-1, 2).T mask = np.logical_and(np.abs(z-z.max()) < bondlen, np.logical_not(mask)) topA, topB = np.arange(len(a))[mask].reshape(-1, 2).T y[topA] += bondlen/3 y[topB] -= bondlen/3 y[top1] += bondlen x[top1] += a.cell[0,0]/(2*nx) x[top2] += a.cell[0,0]/(2*nx) mask = np.abs(z-z.min()) < 0.1*a0 bot1, bot2 = np.arange(len(a))[mask].reshape(-1, 2).T mask = np.logical_and(np.abs(z-z.min()) < bondlen, np.logical_not(mask)) botA, botB = np.arange(len(a))[mask].reshape(-1, 2).T y[botA] += bondlen/3 y[botB] -= bondlen/3 y[bot2] -= bondlen x[bot2] += a.cell[0,0]/(2*nx) x[bot1] += a.cell[0,0]/(2*nx) a.set_scaled_positions(a.get_scaled_positions()%1.0) return bulk, a
def dia_111(sym, a0): sym = string2symbols(sym) if len(sym) == 1: a = Diamond(sym[0], size = [nx, nx, nz], latticeconstant = a0, directions=[ [1,-1,0], [1,1,-2], [1,1,1] ] ) else: a = B3(sym, size = [nx, nx, nz], latticeconstant = a0, directions=[ [1,-1,0], [1,1,-2], [1,1,1] ] ) sx, sy, sz = a.get_cell().diagonal() a.translate([sx/(12*nx), sy/(4*nx), sz/(12*nz)]) return a
def get_formation_energies(energy_dict,ref_dict): formation_energies = {} for key in energy_dict.keys(): #iterate through keys E0 = energy_dict[key] #raw energy name,site = key.split('_') #split key into name/site if 'slab' not in name: #do not include empty site energy (0) if site == '111': E0 -= ref_dict[site] #subtract slab energy if adsorbed #remove - from transition-states formula = name.replace('-','') #get the composition as a list of atomic species composition = string2symbols(formula) #for each atomic species, subtract off the reference energy for atom in composition: E0 -= ref_dict[atom] #round to 3 decimals since this is the accuracy of DFT E0 = round(E0,3) formation_energies[key] = E0 return formation_energies
def random_solid(els, density, sx=None, sy=None): if isinstance(els, str): syms = string2symbols(els) else: syms = "" for sym, n in els: syms += n*sym r = np.random.rand(len(syms), 3) a = ase.Atoms(syms, positions=r, cell=[1,1,1], pbc=True) mass = np.sum(a.get_masses()) if sx is not None and sy is not None: sz = ( 1e24*mass/(density*mol) )/(sx*sy) a.set_cell([sx,sy,sz], scale_atoms=True) else: a0 = ( 1e24*mass/(density*mol) )**(1./3) a.set_cell([a0,a0,a0], scale_atoms=True) a.set_initial_charges([0]*len(a)) return a
def analyse(c, collection, category, category_ref=None): A = [] for name in collection.names: ve = [] # volume, energy pairs for d in c.select(category=category, name=name): try: assert name == d.name ve.append((abs(np.linalg.det(d.cell)), d.energy)) except AttributeError: ve.append((np.nan, np.nan)) # sort according to volume ves = sorted(ve, key=lambda x: x[0]) # EOS eos = EquationOfState([t[0] for t in ves], [t[1] for t in ves]) try: v, e0, B0, B1, R = eos.fit() except (ValueError, TypeError, LinAlgError): (v, e0, B0, B1, R) = (np.nan, np.nan, np.nan, np.nan, np.nan) if not R: R = [np.nan] # sometimes R is an empty array if not isinstance(R, list): R = [R] # sometimes R is not a list e = e0 # formation energy # number of unit formulas per cell nufpc = len(collection[name]) / len(string2symbols(name)) # calculate formation energy wrt category_ref if category_ref: for d in c.select(category=category, name=name, x=1.000): for n in d.numbers: # use gbrv structure (x=1.000) for d1 in c.select(category=category_ref, name=chemical_symbols[n], x=1.000): assert len(set(d1.numbers)) == 1 e = e - d1.energy / len(d1.numbers) e0 = e0 / nufpc e = e / nufpc v = v / nufpc B0 = B0 / kJ * 1.0e24 # GPa A.append((e, e0, v, B0, B1, R[0])) return np.array(A).T
def solvated(symbols): """Extract solvation energies from database. symbols: str Extract only those molecules that contain the chemical elements given by the symbols string (plus water and H+). Data from: Johnson JW, Oelkers EH, Helgeson HC (1992) Comput Geosci 18(7):899. doi:10.1016/0098-3004(92)90029-Q and: Pourbaix M (1966) Atlas of electrochemical equilibria in aqueous solutions. No. v. 1 in Atlas of Electrochemical Equilibria in Aqueous Solutions. Pergamon Press, New York. Returns list of (name, energy) tuples. """ if isinstance(symbols, str): symbols = set(string2symbols(symbols)) if len(_solvated) == 0: for line in _aqueous.splitlines(): energy, formula = line.split(',') name = formula + '(aq)' count, charge, aq = parse_formula(name) energy = float(energy) * 0.001 * units.kcal / units.mol _solvated.append((name, count, charge, aq, energy)) references = [] for name, count, charge, aq, energy in _solvated: for symbol in count: if symbol not in 'HO' and symbol not in symbols: break else: references.append((name, energy)) return references
def get_formation_energies(abinitio_energies, gas_ref_eng, surfaces,adsorbates): """ Finds and prints formation energies from abinitio_energies Returns formation energy dictionary """ ref_dict = {} formation_dict = {} ref_dict['H'] = 0.5*gas_ref_eng['H2_gas'] ref_dict['O'] = gas_ref_eng['H2O_gas'] - 2*ref_dict['H'] ref_dict['C'] = gas_ref_eng['CH4_gas'] - 4*ref_dict['H'] for surf in surfaces: try: ref_dict[surf+'_clean'] = abinitio_energies[surf+'_clean'] except: pass try: ref_dict[surf+'_Oc'] = abinitio_energies[surf+'_Oc'] except: pass #Can also make ref_dict entries for those surfaces relevant to echem for ads in adsorbates: E0 = 0 formula = ads.strip('-') #For transition states composition = string2symbols(formula) for atom in composition: E0 += ref_dict[atom] try: formation_dict[surf+'_'+ads+'_clean'] = abinitio_energies[surf+'_'+ads+'c'] - E0 - ref_dict[surf+'_clean'] except: pass try: formation_dict[surf+'_'+ads+'_Oc'] = abinitio_energies[surf+'_'+ads+'c+Oc'] - E0 - ref_dict[surf+'_Oc'] except: pass for key in sorted(formation_dict.keys()): surf,ads,coverage = key.split('_') energy = formation_dict[key] print "{:10} {:10} {:10} {:10}".format(surf, ads,coverage,energy) return formation_dict
def get_parameters(file, number=2): file = open(file) text = file.read() file.close() # Find elements s = -1 for i in range(number): s = text.find('Optimization', s + 1) s = text.find('\n', s) + 1 e = text.find('parameters', s) elements = tuple(string2symbols(text[s:e].strip())) # Find parameters s = text.find('\n', e) + 1 e = text.find('Fitting', s) - 4 parameters = [] for line in text[s:e].split('\n'): rows = line.split(' ') parameters.append(float(rows[2])) return elements, parameters
def get_composition(species_string): """ Convert string of species into a dictionary of species and the number of each species. :param species_string: A string of the reaction species. Should be a chemical formula string that may also contain '-','&',or,'pe'. 'pe' is a special case corresponding to a proton-electron pair and has the compositon of H, while ele corresponds to an electron and has no associated atoms. :type species: str """ composition = {} # clean up transition states and electrochem species_string = species_string.replace('-','') species_string = species_string.replace('pe','H') species_string = species_string.replace('&','') species_string = species_string.replace('ele','') try: symbs = string2symbols(species_string) for a in set(symbs): composition[a] = symbs.count(a) except ValueError: composition = None return composition
def get_atomization_energy(name): """Determine extrapolated experimental atomization energy from the database. The atomization energy is extrapolated from experimental heats of formation at room temperature, using calculated zero-point energies and thermal corrections. The atomization energy is returned in kcal/mol = 43.36 meV: >>> from ase.units import *; print kcal / mol 0.0433641146392 """ d = data[name] e = d['enthalpy'] z = d['ZPE'] dh = d['thermal correction'] ae = -e + z + dh for a in string2symbols(d['symbols']): h = data[a]['enthalpy'] dh = data[a]['thermal correction'] ae += h - dh return ae
def run(argv=None): if argv is None: argv = sys.argv[1:] elif isinstance(argv, str): argv = argv.split() parser = build_parser() opt, args = parser.parse_args(argv) if len(args) != 1: parser.error("incorrect number of arguments") name = args[0] if world.rank == 0: out = sys.stdout#open('%s-%s.results' % (name, opt.identifier), 'w') else: out = devnull a = None try: symbols = string2symbols(name) except ValueError: # name was not a chemical formula - must be a file name: atoms = read(name) else: if opt.crystal_structure: a = opt.lattice_constant if a is None: a = estimate_lattice_constant(name, opt.crystal_structure, opt.c_over_a) out.write('Using an estimated lattice constant of %.3f Ang\n' % a) atoms = bulk(name, opt.crystal_structure, a, covera=opt.c_over_a, orthorhombic=opt.orthorhombic, cubic=opt.cubic) else: try: # Molecule? atoms = molecule(name) except NotImplementedError: if len(symbols) == 1: # Atom atoms = Atoms(name) elif len(symbols) == 2: # Dimer atoms = Atoms(name, positions=[(0, 0, 0), (opt.bond_length, 0, 0)]) else: raise ValueError('Unknown molecule: ' + name) if opt.magnetic_moment: magmom = opt.magnetic_moment.split(',') atoms.set_initial_magnetic_moments(np.tile(magmom, len(atoms) // len(magmom))) if opt.repeat is not None: r = opt.repeat.split(',') if len(r) == 1: r = 3 * r atoms = atoms.repeat([int(c) for c in r]) if opt.gui: view(atoms) return if opt.write_to_file: write(opt.write_to_file, atoms) return if opt.effective_medium_theory: Runner = EMTRunner else: Runner = GPAWRunner if opt.fit: strains = np.linspace(0.98, 1.02, 5) else: strains = None if opt.constrain_tags: tags = [int(t) for t in opt.constrain_tags.split(',')] constrain = FixAtoms(mask=[t in tags for t in atoms.get_tags()]) atoms.constraints = [constrain] runner = Runner(name, atoms, strains, tag=opt.identifier, clean=not opt.read, fmax=opt.relax, out=out) if not opt.effective_medium_theory: # Import stuff that eval() may need to know: from gpaw.wavefunctions.pw import PW from gpaw.occupations import FermiDirac, MethfesselPaxton if opt.parameters: input_parameters = eval(open(opt.parameters).read()) else: input_parameters = {} for key in defaults: value = getattr(opt, key) if value is not None: try: input_parameters[key] = eval(value) except (NameError, SyntaxError): input_parameters[key] = value runner.set_parameters(vacuum=opt.vacuum, write_gpw_file=opt.write_gpw_file, **input_parameters) runner.run() runner.summary(plot=opt.plot, a0=a) return runner
def set_output_attrs(self,rxn_parameters): """ :param rxn_parameters: Reaction parameters. :type rxn_parameters: list """ if True in [v in self.mapper._solver_output for v in self.output_variables]: cvgs = self._coverage self._coverage = list(self.solver.get_coverage( rxn_parameters,c0=cvgs)) #verify coverage self._rate = list(self.solver.get_rate(rxn_parameters, coverages=self._coverage)) if ( 'turnover_frequency' in self.output_variables or 'production_rate' in self.output_variables or 'consumption_rate' in self.output_variables or 'rxn_direction' in self.output_variables): self._turnover_frequency = self.get_turnover_frequency( rxn_parameters) if 'selectivity' in self.output_variables: self._selectivity = self.get_selectivity(rxn_parameters) self.output_labels['selectivity'] = self.gas_names if 'carbon_selectivity' in self.output_variables: weights = [] for g in self.gas_names: name,site = g.split('_') weight = string2symbols(name).count('C') weights.append(weight) self._carbon_selectivity = self.get_selectivity(rxn_parameters,weights=weights) self.output_labels['carbon_selectivity'] = self.gas_names if 'rate_control' in self.output_variables: self._rate_control = self.get_rate_control(rxn_parameters) self.output_labels['rate_control'] = [self.gas_names,self.parameter_names] if 'selectivity_control' in self.output_variables: self._selectivity_control = self.get_selectivity_control(rxn_parameters) self.output_labels['selectivity_control'] = [self.gas_names,self.parameter_names] if 'rxn_order' in self.output_variables: self._rxn_order = self.get_rxn_order(rxn_parameters) self.output_labels['rxn_order'] = [self.gas_names,self.gas_names] if 'apparent_activation_energy' in self.output_variables: self._apparent_activation_energy = self.get_apparent_activation_energy(rxn_parameters) self.output_labels['apparent_activation_energy'] = self.gas_names if 'interacting_energy' in self.output_variables: if self.adsorbate_interaction_model in [None,'ideal']: self._interacting_energy = rxn_parameters else: self._interacting_energy = self.get_interacting_energies(rxn_parameters) self.output_labels['interacting_energy'] = self.adsorbate_names+self.transition_state_names if 'directional_rates' in self.output_variables: self._directional_rates = self.get_directional_rates(rxn_parameters) self.output_labels['directional_rates'] = [str(rxn) + ' forward' for rxn in self.elementary_rxns] + \ [str(rxn) + ' reverse' for rxn in self.elementary_rxns] if 'turnover_frequency' in self.output_variables: self.output_labels['turnover_frequency'] = self.gas_names for out in self.output_variables: if out == 'production_rate': self._production_rate = [max(0,r) for r in self._turnover_frequency] self.output_labels['production_rate'] = self.gas_names if out == 'consumption_rate': self._consumption_rate = [max(0,-r) for r in self._turnover_frequency] self.output_labels['consumption_rate'] = self.gas_names if out == 'forward_rate': self._forward_rate = [max(0,r) for r in self._rate] self.output_labels['forward_rate'] = self.elementary_rxns if out == 'reverse_rate': self._reverse_rate = [max(0,-r) for r in self._rate] self.output_labels['reverse_rate'] = self.elementary_rxns if out == 'rxn_direction': self._rxn_direction = [np.sign(r) for r in self._turnover_frequency] self.output_labels['rxn_direction'] = self.elementary_rxns if out == 'rate_constant': self._rate_constant = list(self._kf)+list(self._kr) self.output_labels['rate_constant'] = self.elementary_rxns + self.elementary_rxns if out == 'forward_rate_constant': self._forward_rate_constant = list(self._kf) self.output_labels['forward_rate_constant'] = self.elementary_rxns if out == 'reverse_rate_constant': self._reverse_rate_constant = list(self._kr) self.output_labels['reverse_rate_constant'] = self.elementary_rxns if out == 'equilibrium_constant': self._equilibrium_constant = [kf/kr for kf,kr in zip(self._kf,self._kr)] self.output_labels['equilibrium_constant'] = self.elementary_rxns
def bulk(name, crystalstructure=None, a=None, c=None, covera=None, u=None, orthorhombic=False, cubic=False): """Creating bulk systems. Crystal structure and lattice constant(s) will be guessed if not provided. name: str Chemical symbol or symbols as in 'MgO' or 'NaCl'. crystalstructure: str Must be one of sc, fcc, bcc, hcp, diamond, zincblende, rocksalt, cesiumchloride, fluorite or wurtzite. a: float Lattice constant. c: float Lattice constant. covera: float c/a raitio used for hcp. Default is ideal ratio: sqrt(8/3). u: float Internal coordinate for Wurtzite structure. orthorhombic: bool Construct orthorhombic unit cell instead of primitive cell which is the default. cubic: bool Construct cubic unit cell if possible. """ if covera is not None and c is not None: raise ValueError("Don't specify both c and c/a!") xref = None if name in chemical_symbols: Z = atomic_numbers[name] ref = reference_states[Z] if ref is not None: xref = ref['symmetry'] if crystalstructure is None: crystalstructure = xref if a is None: if xref != crystalstructure: raise ValueError('You need to specify the lattice constant.') a = ref['a'] if crystalstructure in ['hcp', 'wurtzite']: cubic = False if c is not None: covera = c / a elif covera is None: if xref == crystalstructure: covera = ref['c/a'] else: covera = sqrt(8 / 3) if orthorhombic and crystalstructure != 'sc': return _orthorhombic_bulk(name, crystalstructure, a, covera, u) if cubic and crystalstructure in ['bcc', 'cesiumchloride']: return _orthorhombic_bulk(name, crystalstructure, a, covera) if cubic and crystalstructure != 'sc': return _cubic_bulk(name, crystalstructure, a) if crystalstructure == 'sc': atoms = Atoms(name, cell=(a, a, a), pbc=True) elif crystalstructure == 'fcc': b = a / 2 atoms = Atoms(name, cell=[(0, b, b), (b, 0, b), (b, b, 0)], pbc=True) elif crystalstructure == 'bcc': b = a / 2 atoms = Atoms(name, cell=[(-b, b, b), (b, -b, b), (b, b, -b)], pbc=True) elif crystalstructure == 'hcp': atoms = Atoms(2 * name, scaled_positions=[(0, 0, 0), (1 / 3, 2 / 3, 0.5)], cell=[(a, 0, 0), (-a / 2, a * sqrt(3) / 2, 0), (0, 0, covera * a)], pbc=True) elif crystalstructure == 'diamond': atoms = bulk(2 * name, 'zincblende', a) elif crystalstructure == 'zincblende': s1, s2 = string2symbols(name) atoms = bulk(s1, 'fcc', a) + bulk(s2, 'fcc', a) atoms.positions[1] += a / 4 elif crystalstructure == 'rocksalt': s1, s2 = string2symbols(name) atoms = bulk(s1, 'fcc', a) + bulk(s2, 'fcc', a) atoms.positions[1, 0] += a / 2 elif crystalstructure == 'cesiumchloride': s1, s2 = string2symbols(name) atoms = bulk(s1, 'sc', a) + bulk(s2, 'sc', a) atoms.positions[1, :] += a / 2 elif crystalstructure == 'fluorite': s1, s2, s3 = string2symbols(name) atoms = bulk(s1, 'fcc', a) + bulk(s2, 'fcc', a) + bulk(s3, 'fcc', a) atoms.positions[1, :] += a / 4 atoms.positions[2, :] += a * 3 / 4 elif crystalstructure == 'wurtzite': u = u or 0.25 + 1 / 3 / covera**2 atoms = Atoms(2 * name, scaled_positions=[(0, 0, 0), (1 / 3, 2 / 3, 0.5 - u), (1 / 3, 2 / 3, 0.5), (0, 0, 1 - u)], cell=[(a, 0, 0), (-a / 2, a * sqrt(3) / 2, 0), (0, 0, a * covera)], pbc=True) else: raise ValueError('Unknown crystal structure: ' + crystalstructure) return atoms
def evaluate_rate_expression(rate_expr, parameters={}): """Evaluates an expression for a typical kMC rate constant. External parameters can be passed in as dictionary, like the following: parameters = {'p_CO':{'value':1}, 'T':{'value':1}} or as a list of parameters: parameters = [Parameter(), ... ] """ import tokenize import StringIO import math from kmos import units # convert parameters to dict if passed as list of Parameters() if type(parameters) is list: param_dict = {} for parameter in parameters: param_dict[parameter.name] = {'value': parameter.value} parameters = param_dict if not rate_expr: rate_const = 0.0 else: replaced_tokens = [] # replace some aliases rate_expr = rate_expr.replace('beta', '(1./(kboltzmann*T))') try: input = StringIO.StringIO(rate_expr).readline tokens = list(tokenize.generate_tokens(input)) except: raise Exception('Could not tokenize expression: %s' % input) for i, token, _, _, _ in tokens: if token in ['sqrt', 'exp', 'sin', 'cos', 'pi', 'pow', 'log']: replaced_tokens.append((i, 'math.' + token)) elif token in dir(units): replaced_tokens.append((i, str(eval('units.' + token)))) elif token.startswith('m_'): from ase.atoms import string2symbols from ase.data import atomic_masses from ase.data import atomic_numbers species_name = '_'.join(token.split('_')[1:]) symbols = string2symbols(species_name) replaced_tokens.append((i, '%s' % sum([atomic_masses[atomic_numbers[symbol]] for symbol in symbols]))) elif token.startswith('mu_'): # evaluate gas phase chemical potential if among # available JANAF tables if from current temperature # and corresponding partial pressure from kmos import species species_name = '_'.join(token.split('_')[1:]) if species_name in dir(species): if not 'T' in parameters: raise Exception('Need "T" in parameters to evaluate chemical potential.') if not ('p_%s' % species_name) in parameters: raise Exception('Need "p_%s" in parameters to evaluate chemical potential.' % species_name) replaced_tokens.append((i, 'species.%s.mu(%s,%s)' % ( species_name, parameters['T']['value'], parameters['p_%s' % species_name]['value'], ))) else: print('No JANAF table assigned for %s' % species_name) print('Setting chemical potential to zero') replaced_tokens.append((i, '0')) elif token in parameters: parameter_str = str(parameters[token]['value']) # replace units used in parameters for unit in units.keys: parameter_str = parameter_str.replace( unit, '%s' % eval('units.%s' % unit)) replaced_tokens.append((i, parameter_str)) else: replaced_tokens.append((i, token)) rate_expr = tokenize.untokenize(replaced_tokens) try: rate_const = eval(rate_expr) except Exception, e: raise UserWarning( "Could not evaluate rate expression: %s\nException: %s" \ % (rate_expr, e))
def convpar(p): """ Convert a parameter set from convenient Python dictionary to the format expected by the Fortran kernels. """ if 'el' not in p: return p els = p['el'] nel = len(els) q = { } for name, values in p.items(): if isinstance(values, dict): # This is a dictionary. We need to first understand what it is and # then convert to the appropriate list m = 0 for itype, value in values: if itype[0] == '_': continue # Ask ASE to turn this into a list of symbols syms = string2symbols(itype) # Now turn this into a list of indices nums = [ els.index(sym) for sym in syms ] # We need to know the maximum number of symbols m = max(m, nums) default = 0.0 if '__default__' in values: default = values['__default__'] if m == 2: # These are pair indices new_values = [ default ]*pair_index(nel,nel,nel) elif m == 3: # These are triplet indices new_values = [ default ]*triplet_index(nel,nel,nel,nel) else: raise RuntimeError("Parameter '%s' appears to involve " \ "interaction between %i atoms. Do not know "\ "how to handle this." % ( name, nel )) for itype, value in values: if itype[0] == '_': continue # Ask ASE to turn this into a list of symbols syms = string2symbols(itype) # Now turn this into a list of indices nums = [ els.index(sym) for sym in syms ] if len(nums) == m: # Set value if m == 2: i,j = nums new_values[pair_index(i,j,nel)] = value elif m == 3: i,j,k = nums new_values[triple_index(i,j,k,nel)] = value else: # We have fewer values than we need if m == 3 and len(nums) == 1: [k] = nums for i in range(nel): for j in range(nel): # There is six possible permutations new_values[triple_index(i,j,k,nel)] = value new_values[triple_index(i,k,j,nel)] = value new_values[triple_index(k,j,i,nel)] = value new_values[triple_index(j,k,i,nel)] = value new_values[triple_index(k,i,j,nel)] = value new_values[triple_index(i,j,k,nel)] = value elif m == 3 and len(nums) == 2: [i,j] = nums for k in range(nel): # There is six possible permutations new_values[triple_index(i,j,k,nel)] = value new_values[triple_index(i,k,j,nel)] = value new_values[triple_index(k,j,i,nel)] = value new_values[triple_index(j,k,i,nel)] = value new_values[triple_index(k,i,j,nel)] = value new_values[triple_index(i,j,k,nel)] = value else: raise RuntimeError("Parameter '%s' appears to involve " \ "interaction between %i atoms, but " \ "only %i elements were provied. Do " \ "not know how to handle this." \ % ( name, nel, len(nums) )) values = new_values q[name] = values return q