def test_reduce_to_primitive(comparator): atoms1 = crystal(symbols=['V', 'Li', 'O'], basis=[(0.000000, 0.000000, 0.000000), (0.333333, 0.666667, 0.000000), (0.333333, 0.000000, 0.250000)], spacegroup=167, cellpar=[5.123, 5.123, 13.005, 90., 90., 120.], size=[1, 1, 1], primitive_cell=False) atoms2 = crystal(symbols=['V', 'Li', 'O'], basis=[(0.000000, 0.000000, 0.000000), (0.333333, 0.666667, 0.000000), (0.333333, 0.000000, 0.250000)], spacegroup=167, cellpar=[5.123, 5.123, 13.005, 90., 90., 120.], size=[1, 1, 1], primitive_cell=True) try: # Tell the comparator to reduce to primitive cell comparator.to_primitive = True assert comparator.compare(atoms1, atoms2) except SpgLibNotFoundError: pass # Reset the comparator to its original state comparator.to_primitive = False
def stru_dict_to_atoms(dct: dict, **kwargs) -> Atoms: """Parse a dictionary of structure information to an ase.Atoms object.""" return crystal(symbols=list(map(atom_dict_to_atom, dct['atoms'])), cellpar=lat_dict_to_list(dct["lattice"]), spacegroup=dct["space_group"], occupancies=get_occ_list(dct["atoms"]), **kwargs)
def test_bases_from_struct(db_test_app): db_test_app.get_or_create_computer() with resource_context("basis_sets", "sto3g") as path: nfiles, nuploaded = BasisSetData.upload_basisset_family( path, "sto3g", "group of sto3g basis sets") # MgO import ase # noqa: F401 from ase.spacegroup import crystal atoms = crystal( symbols=[12, 8], basis=[[0, 0, 0], [0.5, 0.5, 0.5]], spacegroup=225, cellpar=[4.21, 4.21, 4.21, 90, 90, 90], ) # type: ase.Atoms # atoms[0].tag = 1 # atoms[1].tag = 1 atoms.set_tags([1, 1, 0, 0, 0, 0, 0, 0]) structure_data_cls = DataFactory("structure") struct = structure_data_cls(ase=atoms) bases_dict = BasisSetData.get_basissets_by_kind(struct, "sto3g") # print(bases_dict) assert set(bases_dict.keys()) == set(["Mg", "Mg1", "O"]) assert bases_dict["Mg"].get_basis_family_names() == ["sto3g"]
def test_skutterudite(): # A CoSb3 skutterudite unit cell containing 32 atoms skutterudite = crystal(('Co', 'Sb'), basis=[(0.25, 0.25, 0.25), (0.0, 0.335, 0.158)], spacegroup=204, cellpar=[9.04, 9.04, 9.04, 90, 90, 90]) assert len(skutterudite) == 32 correct_pos = np.array([[0.25, 0.25, 0.25], [0.75, 0.75, 0.25], [0.75, 0.25, 0.75], [0.25, 0.75, 0.75], [0.75, 0.75, 0.75], [0.25, 0.25, 0.75], [0.25, 0.75, 0.25], [0.75, 0.25, 0.25], [0., 0.335, 0.158], [0., 0.665, 0.158], [0., 0.335, 0.842], [0., 0.665, 0.842], [0.158, 0., 0.335], [0.158, 0., 0.665], [0.842, 0., 0.335], [0.842, 0., 0.665], [0.335, 0.158, 0.], [0.665, 0.158, 0.], [0.335, 0.842, 0.], [0.665, 0.842, 0.], [0.5, 0.835, 0.658], [0.5, 0.165, 0.658], [0.5, 0.835, 0.342], [0.5, 0.165, 0.342], [0.658, 0.5, 0.835], [0.658, 0.5, 0.165], [0.342, 0.5, 0.835], [0.342, 0.5, 0.165], [0.835, 0.658, 0.5], [0.165, 0.658, 0.5], [0.835, 0.342, 0.5], [0.165, 0.342, 0.5]]) assert np.allclose(skutterudite.get_scaled_positions(), correct_pos)
def test_ase_add_structure(lmp): from ase import spacegroup a = 4.2 alpha = 90 alpha_r = math.radians(alpha) symbols = ['Mg', 'O'] positions = [(0, 0, 0), (0.5, 0.5, 0.5)] structure = spacegroup.crystal(symbols, basis=positions, spacegroup=225, cellpar=[a, a, a, alpha, alpha, alpha]) velocities = np.random.random((len(structure), 3)) structure.set_velocities(velocities) elements = list({(atom.symbol, atom.mass) for atom in structure}) lmp.system.add_ase_structure(structure, elements=elements) assert lmp.system.total == len(structure) assert np.all(np.isclose(lmp.box.lengths, (a, a, a))) assert np.all(np.isclose(lmp.box.angles, (alpha_r, alpha_r, alpha_r))) assert np.all(np.isclose(lmp.box.origin, (0, 0, 0))) print(lmp.system.velocities) print(structure.get_velocities()) print(lmp.system.velocities - structure.get_velocities()) assert np.all( np.isclose(lmp.system.positions, structure.positions, atol=1e-6)) assert np.all(np.isclose(lmp.system.velocities, velocities, atol=1e-6))
def compile_crystal(datarow, flavor='pmg'): """ Helper method for representing the MPDS crystal structures in two flavors: either as a Pymatgen Structure object, or as an ASE Atoms object. Attention! These two flavors are not compatible, e.g. primitive vs. crystallographic cell is defaulted, atoms wrapped or non-wrapped into the unit cell etc. Note, that the crystal structures are not retrieved by default, so one needs to specify the fields while retrieval: - cell_abc - sg_n - setting - basis_noneq - els_noneq e.g. like this: {'S':['cell_abc', 'sg_n', 'setting', 'basis_noneq', 'els_noneq']} NB. occupancies are not considered. Args: datarow: (list) Required data to construct crystal structure: [cell_abc, sg_n, setting, basis_noneq, els_noneq] flavor: (str) Either "pmg", or "ase" Returns: - if flavor is pmg, returns Pymatgen Structure object - if flavor is ase, returns ASE Atoms object """ if not datarow or not datarow[-1]: return None cell_abc, sg_n, setting, basis_noneq, els_noneq = \ datarow[-5], int(datarow[-4]), datarow[-3], datarow[-2], datarow[-1] if flavor == 'pmg': return Structure.from_spacegroup( sg_n, Lattice.from_parameters(*cell_abc), els_noneq, basis_noneq ) elif flavor == 'ase' and use_ase: atom_data = [] setting = 2 if setting == '2' else 1 for num, i in enumerate(basis_noneq): atom_data.append(Atom(els_noneq[num], tuple(i))) return crystal( atom_data, spacegroup=sg_n, cellpar=cell_abc, primitive_cell=True, setting=setting, onduplicates='replace' ) else: raise APIError("Crystal structure treatment unavailable")
def test_write_results(self): # test to see if results are correctly written to file descriptor = PRDF(configs=self.configs) structure = crystal(['Na', 'Cl'], [(0, 0, 0), (0.5, 0.5, 0.5)], spacegroup=225, cellpar=[5.64, 5.64, 5.64, 90, 90, 90]) descriptor.calculate(structure)
def getSpeciesListCIF(inputFile): ''' inputFile is the name of an input file use ASE at this point to quickly parse file DOES NOTHING ABOUT FRACTIONAL OCCUPANCY ''' from ase.io.cif import parse_cif aseParser = parse_cif(inputFile) for name, c in aseParser: scaled_positions = np.array([ c['_atom_site_fract_x'], c['_atom_site_fract_y'], c['_atom_site_fract_z'] ]).T crys = crystal(c['_atom_site_type_symbol'], basis=scaled_positions, cellpar=[ c['_cell_length_a'], c['_cell_length_b'], c['_cell_length_c'], c['_cell_angle_alpha'], c['_cell_angle_beta'], c['_cell_angle_gamma'] ], spacegroup=c['_symmetry_int_tables_number']) atoms = Atoms(symbols=c['_atom_site_type_symbol'], scaled_positions=scaled_positions, cell=[ c['_cell_length_a'], c['_cell_length_b'], c['_cell_length_c'], c['_cell_angle_alpha'], c['_cell_angle_beta'], c['_cell_angle_gamma'] ], info={ 'spacegroup': ASESpacegroup(c['_symmetry_int_tables_number']) }) print 'pbc=False', len(crys), len(atoms) yield atoms
def refine(ase_obj, accuracy=1E-03): """ Refine ASE structure using spglib Args: ase_obj: (object) ASE structure accuracy: (float) spglib tolerance, normally within [1E-02, 1E-04] Returns: Refined ASE structure (object) *or* None None *or* error (str) """ try: symmetry = spglib.get_spacegroup(ase_obj, symprec=accuracy) lattice, positions, numbers = spglib.refine_cell(ase_obj, symprec=accuracy) except: return None, 'Error while structure refinement' try: spacegroup = int(symmetry.split()[1].replace("(", "").replace(")", "")) except (ValueError, IndexError): return None, 'Symmetry error (coinciding atoms?) in structure' try: return crystal(Atoms(numbers=numbers, cell=lattice, scaled_positions=positions, pbc=True), spacegroup=spacegroup, primitive_cell=True, onduplicates='replace'), None except: return None, 'Unrecognized sites or invalid site symmetry in structure'
def generate_random_perovskite(lat=None): ''' This generates a random valid perovskite structure in ASE format. Useful for testing. Binary and organic perovskites are not considered. ''' if not lat: lat = round(random.uniform(3.5, Perovskite_tilting.OCTAHEDRON_BOND_LENGTH_LIMIT*2), 3) A_site = random.choice(Perovskite_Structure.A) B_site = random.choice(Perovskite_Structure.B) Ci_site = random.choice(Perovskite_Structure.C) Cii_site = random.choice(Perovskite_Structure.C) while covalent_radii[chemical_symbols.index(A_site)] - \ covalent_radii[chemical_symbols.index(B_site)] < 0.05 or \ covalent_radii[chemical_symbols.index(A_site)] - \ covalent_radii[chemical_symbols.index(B_site)] > 0.5: A_site = random.choice(Perovskite_Structure.A) B_site = random.choice(Perovskite_Structure.B) return crystal( [A_site, B_site, Ci_site, Cii_site], [(0.5, 0.25, 0.0), (0.0, 0.0, 0.0), (0.0, 0.25, 0.0), (0.25, 0.0, 0.75)], spacegroup=62, cellpar=[lat*math.sqrt(2), 2*lat, lat*math.sqrt(2), 90, 90, 90] )
def cubic_perovskite(species, cell_par=[6, 6, 6, 90, 90, 90], repetitions=[1, 1, 1]): ''' Function to build a perovskite cell using the crystal function is ASE. Args: species (str): Element symbols cell_par (list): Six floats/ints specifying 3 unit cell lengths and 3 unit cell angles. repetitions (list): Three floats specifying the expansion of the cell in x,y,z directions. Returns: SMACT Lattice object of the unit cell, ASE crystal system of the unit cell. ''' system = crystal((species), basis=[(0, 0, 0), (0.5, 0.5, 0.5), (0.5, 0.5, 0)], spacegroup=221, size=repetitions, cellpar=cell_par) sites_list = [] oxidation_states = [[2]] + [[4]] + [[-2]] * 3 for site in zip(system.get_scaled_positions(), oxidation_states): sites_list.append(Site(site[0], site[1])) return Lattice(sites_list, oxidation_states), system
def getcrystal(self): self.getsetting() self.crystal = crystal(self.species, basis=self.basis, spacegroup=self.spacegroup, cellpar = self.cell) self.natoms = self.crystal.get_global_number_of_atoms()
def test_spacegroup_crystal(): import numpy as np from ase.spacegroup import crystal from ase.io import write # A diamond unit cell diamond = crystal('C', [(0, 0, 0)], spacegroup=227, cellpar=[3.57, 3.57, 3.57, 90, 90, 90]) # Check that we can write to trajectory: write('c.traj', diamond) assert len(diamond) == 8 correct_pos = np.array([[0., 0., 0.], [0., 0.5, 0.5], [0.5, 0.5, 0.], [0.5, 0., 0.5], [0.75, 0.25, 0.75], [0.25, 0.25, 0.25], [0.25, 0.75, 0.75], [0.75, 0.75, 0.25]]) assert np.allclose(diamond.get_scaled_positions(), correct_pos) # A CoSb3 skutterudite unit cell containing 32 atoms skutterudite = crystal(('Co', 'Sb'), basis=[(0.25, 0.25, 0.25), (0.0, 0.335, 0.158)], spacegroup=204, cellpar=[9.04, 9.04, 9.04, 90, 90, 90]) assert len(skutterudite) == 32 correct_pos = np.array([[0.25, 0.25, 0.25], [0.75, 0.75, 0.25], [0.75, 0.25, 0.75], [0.25, 0.75, 0.75], [0.75, 0.75, 0.75], [0.25, 0.25, 0.75], [0.25, 0.75, 0.25], [0.75, 0.25, 0.25], [0., 0.335, 0.158], [0., 0.665, 0.158], [0., 0.335, 0.842], [0., 0.665, 0.842], [0.158, 0., 0.335], [0.158, 0., 0.665], [0.842, 0., 0.335], [0.842, 0., 0.665], [0.335, 0.158, 0.], [0.665, 0.158, 0.], [0.335, 0.842, 0.], [0.665, 0.842, 0.], [0.5, 0.835, 0.658], [0.5, 0.165, 0.658], [0.5, 0.835, 0.342], [0.5, 0.165, 0.342], [0.658, 0.5, 0.835], [0.658, 0.5, 0.165], [0.342, 0.5, 0.835], [0.342, 0.5, 0.165], [0.835, 0.658, 0.5], [0.165, 0.658, 0.5], [0.835, 0.342, 0.5], [0.165, 0.342, 0.5]]) assert np.allclose(skutterudite.get_scaled_positions(), correct_pos)
def test_NaCl_minimize(): from ase.calculators.lammpsrun import LAMMPS from ase.spacegroup import crystal from ase.data import atomic_numbers, atomic_masses from ase.optimize import QuasiNewton from ase.constraints import UnitCellFilter from numpy.testing import assert_allclose a = 6.15 n = 4 nacl = crystal(['Na', 'Cl'], [(0, 0, 0), (0.5, 0.5, 0.5)], spacegroup=225, cellpar=[a, a, a, 90, 90, 90]).repeat((n, n, n)) # Buckingham parameters from # https://physics.stackexchange.com/questions/250018 pair_style = 'buck/coul/long 12.0' pair_coeff = ['1 1 3796.9 0.2603 124.90'] pair_coeff += ['2 2 1227.2 0.3214 124.90'] pair_coeff += ['1 2 4117.9 0.3048 0.0'] masses = [ '1 {}'.format(atomic_masses[atomic_numbers['Na']]), '2 {}'.format(atomic_masses[atomic_numbers['Cl']]) ] with LAMMPS( specorder=['Na', 'Cl'], pair_style=pair_style, pair_coeff=pair_coeff, masses=masses, atom_style='charge', kspace_style='pppm 1.0e-5', keep_tmp_files=True, ) as calc: for a in nacl: if a.symbol == 'Na': a.charge = +1. else: a.charge = -1. nacl.set_calculator(calc) assert_allclose(nacl.get_potential_energy(), -1896.216737561538, atol=1e-4, rtol=1e-4) nacl.get_potential_energy() ucf = UnitCellFilter(nacl) dyn = QuasiNewton(ucf, force_consistent=False) dyn.run(fmax=1.0E-2) assert_allclose(nacl.get_potential_energy(), -1897.208861729178, atol=1e-4, rtol=1e-4)
def read_trajectory(self, traj_file_list): from ase.io.trajectory import Trajectory from ase import Atoms from ase.spacegroup import crystal from fractions import Fraction """Reads a list of GULP opti trajectory files, and extracts the starting geometry and coordinate information into a list of ASE atoms.""" trajectory = [] for step in traj_file_list: cell = [] position_str = [] with open(step) as f: while True: line = f.readline() if not line: break # As the output is well structured, and we need only the structure information. # However, the end of coordinates is not well defined, so this is used instead. # More stopping criteria can be added. if line.startswith("species") or line.startswith( "reaxFFtol"): break if line.startswith("cell"): pos_line = f.readline() pos_line = pos_line.split() cell = [float(Fraction(x)) for x in pos_line] elif line.startswith('frac'): coord_line = f.readline() # Trying to ensure that only relevant lines are read. while "core" in coord_line.lower( ) or "shel" in coord_line.lower( ) or "bshe" in coord_line.lower(): position_str.append(coord_line.split()) coord_line = f.readline() # convert information to ASE atoms and append to trajectory atomic_symbols = [x[0] for x in position_str] positions = [[float(Fraction(x)) for x in y[2:5]] for y in position_str] # running with symmetry constraints only output assymetric information for cells if self.parameters.symmetry: ase_atoms = crystal( symbols=atomic_symbols, basis=positions, spacegroup=self.atoms.info['spacegroup'].no, cellpar=cell, primitive_cell=self.atoms.info['unit_cell'] == 'primitive') else: ase_atoms = Atoms(atomic_symbols, cell=cell, pbc=True) ase_atoms.set_scaled_positions(positions) trajectory.append(ase_atoms) return trajectory
def make_struc_super(alat, dim): unitcell = crystal('Si', [(0, 0, 0)], spacegroup=227, cellpar=[alat, alat, alat, 90, 90, 90], primitive_cell=True) multiplier = np.identity(3) * dim ase_supercell = make_supercell(unitcell, multiplier) structure = Struc(ase2struc(ase_supercell)) return structure
def test_binaries(self): # check if the diffraction fingerprint calculation works for more than one element descriptor = DISH(configs=self.configs) # build binary structure structure = crystal(['Na', 'Cl'], [(0, 0, 0), (0.5, 0.5, 0.5)], spacegroup=225, cellpar=[5.64, 5.64, 5.64, 90, 90, 90]) descriptor.calculate(structure)
def cubic_perovskite(species,cell_par=[6,6,6,90,90,90],repetitions=[1,1,1]): system = crystal((species), basis=[(0,0,0), (0.5, 0.5, 0.5), (0.5, 0.5, 0)], spacegroup=221, size = repetitions, cellpar=cell_par) sites_list = [] oxidation_states = [[2]] + [[4]] + [[-2]]*3 for site in zip(system.get_scaled_positions(),oxidation_states): sites_list.append(Site(site[0],site[1])) return Lattice(sites_list, oxidation_states), system
def make_unitcell_central_Li(write_file=False): """ creates an Si unit cell with the central tetrahedral site occupied by Li """ unitcell = crystal('Si', [(0, 0, 0)], spacegroup=227, cellpar=3 * [Si_alat] + 3 * [90]) unitcell.extend(Atoms('Li', positions=[tuple(3 * [0.5 * Si_alat])])) if write_file: write(structures_folder_path + 'unitcell_central_Li.cif', unitcell) return Struc(ase2struc(unitcell))
def make_Si_unitcell(write_file=False): """ creates an Si unit cell with no Li """ unitcell = crystal('Si', [(0, 0, 0)], spacegroup=227, cellpar=3 * [Si_alat] + 3 * [90]) if write_file: write(structures_folder_path + 'unitcell_Si.cif', unitcell) structure = Struc(ase2struc(unitcell)) structure.content['species']['Li'] = {'mass': 6.939, 'kind': 2} return structure
def test_compute_symmetry_simple(db_test_app): # MgO atoms = crystal( symbols=[12, 8], basis=[[0, 0, 0], [0.5, 0.5, 0.5]], spacegroup=225, cellpar=[4.21, 4.21, 4.21, 90, 90, 90], ) dataset = compute_symmetry_dataset(atoms, symprec=0.01, angle_tolerance=None) assert dataset["number"] == 225 assert len(dataset["rotations"]) == 192
def wurtzite(species, cell_par=[2,2,6,90,90,120],repetitions=[1,1,1]): system = crystal((species), basis=[(2./3.,1./3.,0),(2./3.,1./3.,5./8.)], spacegroup=186, size = repetitions, cellpar=[3, 3, 6, 90,90,120]) sites_list = [] oxidation_states = [[1],[2],[3],[4]] + [[-1],[-2],[-3],[-4]] for site in zip(system.get_scaled_positions(),oxidation_states): sites_list.append(Site(site[0],site[1])) return Lattice(sites_list, oxidation_states), system
def make_struc(alat): """ Creates the crystal structure using ASE. :param alat: Lattice parameter in angstrom :return: structure object converted from ase """ unitcell = crystal('Ag', [(0, 0, 0)], spacegroup=225, cellpar=[alat, alat, alat, 90, 90, 90]) #multiplier = numpy.identity(3) * 2 #ase_supercell = make_supercell(unitcell, multiplier) structure = Struc(ase2struc(unitcell)) return structure
def get_atoms(self, store_tags=False, primitive_cell=False, subtrans_included=True, fractional_occupancies=True) -> Atoms: """Returns an Atoms object from a cif tags dictionary. See read_cif() for a description of the arguments.""" if primitive_cell and subtrans_included: raise RuntimeError( 'Primitive cell cannot be determined when sublattice ' 'translations are included in the symmetry operations listed ' 'in the CIF file, i.e. when `subtrans_included` is True.') cell = self.get_cell() assert cell.rank in [0, 3] kwargs: Dict[str, Any] = {} if store_tags: kwargs['info'] = self._tags.copy() if fractional_occupancies: occupancies = self._get_fractional_occupancies() else: occupancies = None if occupancies is not None: # no warnings in this case kwargs['onduplicates'] = 'keep' # The unsymmetrized_structure is not the asymmetric unit # because the asymmetric unit should have (in general) a smaller cell, # whereas we have the full cell. unsymmetrized_structure = self.get_unsymmetrized_structure() if cell.rank == 3: spacegroup = self.get_spacegroup(subtrans_included) atoms = crystal(unsymmetrized_structure, spacegroup=spacegroup, setting=spacegroup.setting, occupancies=occupancies, primitive_cell=primitive_cell, **kwargs) else: atoms = unsymmetrized_structure if kwargs.get('info') is not None: atoms.info.update(kwargs['info']) if occupancies is not None: # Compile an occupancies dictionary occ_dict = {} for i, sym in enumerate(atoms.symbols): occ_dict[str(i)] = {sym: occupancies[i]} atoms.info['occupancy'] = occ_dict return atoms
def make_from_ase(self, supercell): from ase.spacegroup import crystal from ase.build import make_supercell a = self._a ni = crystal(self._name, [(0, 0, 0)], spacegroup=self._space_group, cellpar=[a, a, a, 90, 90, 90]) if len(supercell) != 3: raise Exception("Supercell must be a vector [a b c]") make_supercell(ni, supercell)
def test_approximate_rotational_invariance(self): descriptor = DISH(configs=self.configs) # build crystal structures - two different random rotations fcc_al = crystal('Al', [(0, 0, 0)], spacegroup=225, cellpar=[4.05, 4.05, 4.05, 90, 90, 90]) fcc_all_supercell_rot1 = create_supercell(fcc_al, target_nb_atoms=128) fcc_all_supercell_rot2 = create_supercell(fcc_al, target_nb_atoms=128) # rotate 1st structure alphas = (random.random() * 360.0, random.random() * 360.0, random.random() * 360.0) fcc_all_supercell_rot1.rotate(alphas[0], 'x', rotate_cell=True, center='COU') fcc_all_supercell_rot1.rotate(alphas[1], 'y', rotate_cell=True, center='COU') fcc_all_supercell_rot1.rotate(alphas[2], 'z', rotate_cell=True, center='COU') # rotate 2nd structure alphas = (random.random() * 360.0, random.random() * 360.0, random.random() * 360.0) fcc_all_supercell_rot2.rotate(alphas[0], 'x', rotate_cell=True, center='COU') fcc_all_supercell_rot2.rotate(alphas[1], 'y', rotate_cell=True, center='COU') fcc_all_supercell_rot2.rotate(alphas[2], 'z', rotate_cell=True, center='COU') # calculate the descriptor descriptor.calculate(fcc_all_supercell_rot1) descriptor.calculate(fcc_all_supercell_rot2) spectrum_rot1 = fcc_all_supercell_rot1.info['descriptor'][ 'diffraction_3d_sh_spectrum'] spectrum_rot2 = fcc_all_supercell_rot2.info['descriptor'][ 'diffraction_3d_sh_spectrum'] # test if the two diffraction fingerprints are different by less than 20% (20% is arbitrary) self.assertLessEqual(np.abs(np.amax(spectrum_rot1 - spectrum_rot2)), 0.20)
def make_struc(alat): """ Creates the crystal structure using ASE. :param alat: Lattice parameter in angstrom :return: structure object converted from ase """ unitcell = crystal('Au', [(0, 0, 0)], spacegroup=225, cellpar=[alat, alat, alat, 90, 90, 90]) #unitcell.edit() natoms_unitcell=(len(unitcell.numbers)) print('number of atoms in the bulk is', natoms_unitcell) structure = Struc(ase2struc(unitcell)) return structure
def make_struc(alat, a): """ Creates the crystal structure using ASE. :param alat: Lattice parameter in angstrom :return: structure object converted from ase """ # set primitive_cell=False if you want to create a simple cubic unit cell with 8 atoms gecell = crystal('Ge', [(0, 0, 0)], spacegroup=227, cell=a, primitive_cell=False) #check how your cell looks like gecell.positions[0][2]=gecell.positions[0][2]+0.00 write('s.cif', gecell) structure = Struc(ase2struc(gecell)) return structure
def make_2x2x2_supercell_1x1x1_central_Li(write_file=False): """ creates a 2x2x2 Si supercell with the 1, 1, 1 cell's central tetrahedral site occupied by Li """ unitcell = crystal('Si', [(0, 0, 0)], spacegroup=227, cellpar=3 * [Si_alat] + 3 * [90]) supercell = make_supercell(unitcell, np.identity(3) * 2) supercell.extend(Atoms('Li', positions=[tuple(3 * [0.5 * Si_alat])])) if write_file: write(structures_folder_path + '2x2x2_supercell_1x1x1_central_Li.cif', supercell) return Struc(ase2struc(supercell))
def test_elements_pairs_rdf(self): # check that the number of unique chemical elements' pairs for the radial distribution function is one # (all chemical species are considered as the same) structure = crystal(['Na', 'Cl'], [(0, 0, 0), (0.5, 0.5, 0.5)], spacegroup=225, cellpar=[5.64, 5.64, 5.64, 90, 90, 90]) # descriptor calculation descriptor = PRDF(configs=self.configs, rdf_only=True) descriptor.calculate(structure) rdf = structure.info['descriptor']['rdf'] self.assertEqual(len(rdf.keys()), 1)
def cubic_perovskite(species,cell_par=[6,6,6,90,90,90],repetitions=[1,1,1]): ''' Function to build a perovskite cell using the crystal function is ASE. Args: species (str): Element symbols cell_par (list): Six floats/ints specifying 3 unit cell lengths and 3 unit cell angles. repetitions (list): Three floats specifying the expansion of the cell in x,y,z directions. Returns: SMACT Lattice object of the unit cell, ASE crystal system of the unit cell. ''' system = crystal((species), basis=[(0,0,0), (0.5, 0.5, 0.5), (0.5, 0.5, 0)], spacegroup=221, size = repetitions, cellpar=cell_par) sites_list = [] oxidation_states = [[2]] + [[4]] + [[-2]]*3 for site in zip(system.get_scaled_positions(),oxidation_states): sites_list.append(Site(site[0],site[1])) return Lattice(sites_list, oxidation_states), system
def wurtzite(species, cell_par=[2,2,6,90,90,120],repetitions=[1,1,1]): ''' Function to build a wurzite cell using the crystal function is ASE. Args: species (str): Element symbols cell_par (list): Six floats/ints specifying 3 unit cell lengths and 3 unit cell angles. repetitions (list): Three floats specifying the expansion of the cell in x,y,z directions. Returns: SMACT Lattice object of the unit cell, ASE crystal system of the unit cell. ''' system = crystal((species), basis=[(2./3.,1./3.,0),(2./3.,1./3.,5./8.)], spacegroup=186, size = repetitions, cellpar=[3, 3, 6, 90,90,120]) sites_list = [] oxidation_states = [[1],[2],[3],[4]] + [[-1],[-2],[-3],[-4]] for site in zip(system.get_scaled_positions(),oxidation_states): sites_list.append(Site(site[0],site[1])) return Lattice(sites_list, oxidation_states), system
def read_jsv(f): """Reads a JSV file.""" natom = nbond = npoly = 0 symbols = [] labels = [] cellpar = basis = title = bonds = poly = origin = shell_numbers = None spacegroup = 1 headline = f.readline().strip() while True: line = f.readline() if not line: break line = line.strip() m = re.match(r"^\[([^]]+)\]\s*(.*)", line) if m is None or not line: continue tag = m.groups()[0].lower() if len(m.groups()) > 1: args = m.groups()[1].split() else: args = [] if tag == "cell": cellpar = [float(x) for x in args] elif tag == "natom": natom = int(args[0]) elif tag == "nbond": nbond = int(args[0]) # optional margin of the bondlengths elif tag == "npoly": npoly = int(args[0]) elif tag == "space_group": spacegroup = Spacegroup(*tuple(int(x) for x in args)) elif tag == "title": title = m.groups()[1] elif tag == "atoms": symbols = [] basis = np.zeros((natom, 3), dtype=float) shell_numbers = -np.ones((natom,), dtype=int) # float? for i in range(natom): tokens = f.readline().strip().split() labels.append(tokens[0]) symbols.append(ase.data.chemical_symbols[int(tokens[1])]) basis[i] = [float(x) for x in tokens[2:5]] if len(tokens) > 5: shell_numbers[i] = float(tokens[5]) # float? elif tag == "bonds": for i in range(nbond): f.readline() bonds = NotImplemented elif tag == "poly": for i in range(npoly): f.readline() poly = NotImplemented elif tag == "origin": origin = NotImplemented else: raise ValueError('Unknown tag: "%s"' % tag) if headline == "asymmetric_unit_cell": atoms = crystal(symbols=symbols, basis=basis, spacegroup=spacegroup, cellpar=cellpar) elif headline == "full_unit_cell": atoms = ase.Atoms(symbols=symbols, scaled_positions=basis, cell=cellpar_to_cell(cellpar)) atoms.info["spacegroup"] = Spacegroup(spacegroup) elif headline == "cartesian_cell": atoms = ase.Atoms(symbols=symbols, positions=basis, cell=cellpar_to_cell(cellpar)) atoms.info["spacegroup"] = Spacegroup(spacegroup) else: raise ValueError('Invalid JSV file type: "%s"' % headline) atoms.info["title"] = title atoms.info["labels"] = labels if bonds is not None: atoms.info["bonds"] = bonds if poly is not None: atoms.info["poly"] = poly if origin is not None: atoms.info["origin"] = origin if shell_numbers is not None: atoms.info["shell_numbers"] = shell_numbers return atoms
def update(self, *args): """ all changes of physical constants are handled here, atoms are set up""" if self.clearing_in_process: return True self.update_element() a_equals = self.lattice_lequals[0].get_active() b_equals = self.lattice_lequals[1].get_active() c_equals = self.lattice_lequals[2].get_active() alpha_equals = self.lattice_aequals[0].get_active() beta_equals = self.lattice_aequals[1].get_active() gamma_equals = self.lattice_aequals[2].get_active() sym = self.spacegroup.get_text() valid = True try: no = int(sym) spg = Spacegroup(no).symbol self.spacegroupinfo.set_label(_('Symbol: %s') % str(spg)) spg = no except: try: no = Spacegroup(sym).no self.spacegroupinfo.set_label(_('Number: %s') % str(no)) spg = no except: self.spacegroupinfo.set_label(_('Invalid Spacegroup!')) valid = False if a_equals == 0: self.lattice_lbuts[0].set_sensitive(True) elif a_equals == 1: self.lattice_lbuts[0].set_sensitive(False) self.lattice_lbuts[0].set_value(self.lattice_lbuts[1].get_value()) elif a_equals == 2: self.lattice_lbuts[0].set_sensitive(False) self.lattice_lbuts[0].set_value(self.lattice_lbuts[2].get_value()) else: self.lattice_lbuts[0].set_sensitive(False) if b_equals == 0: self.lattice_lbuts[1].set_sensitive(True) elif b_equals == 1: self.lattice_lbuts[1].set_sensitive(False) self.lattice_lbuts[1].set_value(self.lattice_lbuts[0].get_value()) elif b_equals == 2: self.lattice_lbuts[1].set_sensitive(False) self.lattice_lbuts[1].set_value(self.lattice_lbuts[2].get_value()) else: self.lattice_lbuts[1].set_sensitive(False) if c_equals == 0: self.lattice_lbuts[2].set_sensitive(True) elif c_equals == 1: self.lattice_lbuts[2].set_sensitive(False) self.lattice_lbuts[2].set_value(self.lattice_lbuts[0].get_value()) elif c_equals == 2: self.lattice_lbuts[2].set_sensitive(False) self.lattice_lbuts[2].set_value(self.lattice_lbuts[1].get_value()) else: self.lattice_lbuts[2].set_sensitive(False) if alpha_equals == 0: self.lattice_abuts[0].set_sensitive(True) elif alpha_equals == 1: self.lattice_abuts[0].set_sensitive(False) self.lattice_abuts[0].set_value(self.lattice_abuts[1].get_value()) elif alpha_equals == 2: self.lattice_abuts[0].set_sensitive(False) self.lattice_abuts[0].set_value(self.lattice_abuts[2].get_value()) else: self.lattice_abuts[0].set_sensitive(False) if beta_equals == 0: self.lattice_abuts[1].set_sensitive(True) elif beta_equals == 1: self.lattice_abuts[1].set_sensitive(False) self.lattice_abuts[1].set_value(self.lattice_abuts[0].get_value()) elif beta_equals == 2: self.lattice_abuts[1].set_sensitive(False) self.lattice_abuts[1].set_value(self.lattice_abuts[2].get_value()) else: self.lattice_abuts[1].set_sensitive(False) if gamma_equals == 0: self.lattice_abuts[2].set_sensitive(True) elif gamma_equals == 1: self.lattice_abuts[2].set_sensitive(False) self.lattice_abuts[2].set_value(self.lattice_abuts[0].get_value()) elif gamma_equals == 2: self.lattice_abuts[2].set_sensitive(False) self.lattice_abuts[2].set_value(self.lattice_abuts[1].get_value()) else: self.lattice_abuts[2].set_sensitive(False) valid = len(self.elements[0][0].get_text()) and valid self.get_data.set_sensitive(valid and self.get_n_elements() == 1 and self.update_element()) self.atoms = None if valid: basis_count = -1 for el in self.elements: if el[-1]: basis_count += 1 if basis_count: symbol_str = '[' basis_str = "[" symbol = [] basis = [] else: symbol_str = '' basis_str = '' basis = None for el in self.elements: if el[-1]: symbol_str += "'" + el[0].get_text() + "'" if basis_count: symbol_str += ',' symbol += [el[0].get_text()] exec('basis += [[float(' + el[1].get_text( ) + '),float(' + el[2].get_text() + '),float(' + el[3] .get_text() + ')]]') else: symbol = el[0].get_text() exec('basis = [[float(' + el[1].get_text() + '),float(' + el[2].get_text() + '),float(' + el[3].get_text( ) + ')]]') basis_str += '[' + el[1].get_text() + ',' + el[2].get_text( ) + ',' + el[3].get_text() + '],' basis_str = basis_str[:-1] if basis_count: symbol_str = symbol_str[:-1] + ']' basis_str += ']' size_str = '(' + str(int(self.size[0].get_value())) + ',' + str( int(self.size[1].get_value())) + ',' + str( int(self.size[2].get_value())) + ')' size = (int(self.size[0].get_value()), int(self.size[1].get_value()), int(self.size[2].get_value())) cellpar_str = '' cellpar = [] for i in self.lattice_lbuts: cellpar_str += str(i.get_value()) + ',' cellpar += [i.get_value()] for i in self.lattice_abuts: cellpar_str += str(i.get_value()) + ',' cellpar += [i.get_value()] cellpar_str = '[' + cellpar_str[:-1] + ']' args = { 'symbols': symbol, 'basis': basis, 'size': size, 'spacegroup': spg, 'cellpar': cellpar } args_str = { 'symbols': symbol_str, 'basis': basis_str, 'size': size_str, 'spacegroup': spg, 'cellpar': cellpar_str } self.pybut.python = py_template % args_str try: self.atoms = crystal(**args) label = label_template % { 'natoms': len(self.atoms), 'symbols': formula(self.atoms.get_atomic_numbers()), 'volume': self.atoms.get_volume() } self.status.set_label(label) except: self.atoms = None self.status.set_markup( _("Please specify a consistent set of atoms.")) else: self.atoms = None self.status.set_markup( _("Please specify a consistent set of atoms."))
from ase.spacegroup import crystal a = 3.21 c = 5.21 mg = crystal('Mg', [(1./3., 2./3., 3./4.)], spacegroup=194, cellpar=[a, a, c, 90, 90, 120])
import numpy as np from ase.spacegroup import crystal from ase.io import write # A diamond unit cell diamond = crystal('C', [(0, 0, 0)], spacegroup=227, cellpar=[3.57, 3.57, 3.57, 90, 90, 90]) # Check that we can write to trajectory: write('c.traj', diamond) assert len(diamond) == 8 correct_pos = np.array([[ 0. , 0. , 0. ], [ 0. , 0.5 , 0.5 ], [ 0.5 , 0.5 , 0. ], [ 0.5 , 0. , 0.5 ], [ 0.75, 0.25, 0.75], [ 0.25, 0.25, 0.25], [ 0.25, 0.75, 0.75], [ 0.75, 0.75, 0.25]]) assert np.allclose(diamond.get_scaled_positions(), correct_pos) # A CoSb3 skutterudite unit cell containing 32 atoms skutterudite = crystal(('Co', 'Sb'), basis=[(0.25, 0.25, 0.25), (0.0, 0.335, 0.158)], spacegroup=204, cellpar=[9.04, 9.04, 9.04, 90, 90, 90]) assert len(skutterudite) == 32
from ase.spacegroup import crystal a = 3.57 diamond = crystal('C', [(0,0,0)], spacegroup=227, cellpar=[a, a, a, 90, 90, 90])
"""Test the ase.geometry module and ase.build.cut() function.""" from __future__ import division import numpy as np from ase.build import cut, bulk from ase.geometry import (get_layers, wrap_positions, crystal_structure_from_cell) from ase.spacegroup import crystal al = crystal('Al', [(0, 0, 0)], spacegroup=225, cellpar=4.05) # Cut out slab of 5 Al(001) layers al001 = cut(al, nlayers=5) correct_pos = np.array([[0., 0., 0.], [0., 0.5, 0.2], [0.5, 0., 0.2], [0.5, 0.5, 0.], [0., 0., 0.4], [0., 0.5, 0.6], [0.5, 0., 0.6], [0.5, 0.5, 0.4], [0., 0., 0.8], [0.5, 0.5, 0.8]]) assert np.allclose(correct_pos, al001.get_scaled_positions()) # Check layers along 001 tags, levels = get_layers(al001, (0, 0, 1)) assert np.allclose(tags, [0, 1, 1, 0, 2, 3, 3, 2, 4, 4]) assert np.allclose(levels, [0., 2.025, 4.05, 6.075, 8.1])
from ase.spacegroup import crystal from ase.calculators.emt import EMT from ase.optimize import QuasiNewton from ase.phonons import Phonons from ase.thermochemistry import CrystalThermo # Set up gold bulk and attach EMT calculator a = 4.078 atoms = crystal('Au', (0., 0., 0.), spacegroup=225, cellpar=[a, a, a, 90, 90, 90], pbc=(1, 1, 1)) calc = EMT() atoms.set_calculator(calc) qn = QuasiNewton(atoms) qn.run(fmax=0.05) potentialenergy = atoms.get_potential_energy() # Phonon analysis N = 5 ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05) ph.run() ph.read(acoustic=True) phonon_energies, phonon_DOS = ph.dos(kpts=(40, 40, 40), npts=3000, delta=5e-4) # Calculate the Helmholtz free energy thermo = CrystalThermo(phonon_energies=phonon_energies, phonon_DOS=phonon_DOS, potentialenergy=potentialenergy, formula_units=4)
if refcell is None: refcell = cryst du = cryst.get_cell()-refcell.get_cell() m = refcell.get_cell() m = inv(m) u = dot(m, du) u = (u+u.T)/2 return array([u[0, 0], u[1, 1], u[2, 2], u[2, 1], u[2, 0], u[1, 0]]) if __name__ == '__main__': from ase.spacegroup import crystal a = 4.194 cryst = crystal(['Mg', 'O'], [(0, 0, 0), (0.5, 0.5, 0.5)], spacegroup=225, cellpar=[a, a, a, 90, 90, 90]) sl = scan_volumes(cryst) print('Volumes: ', end='') for c in sl: print('%.2f (%.1f%%)' % (c.get_volume(), 100*c.get_volume()/cryst.get_volume()), end=' ') print() sl = get_elementary_deformations(cryst) print('Structures: ') print(' Vol A B C alph bet gam') for n, c in enumerate(sl):
from ase.spacegroup import crystal a = 2.87 fe = crystal('Fe', [(0,0,0)], spacegroup=229, cellpar=[a, a, a, 90, 90, 90])
import ase.io as io from ase.build import cut from ase.spacegroup import crystal a = 9.04 skutterudite = crystal(('Co', 'Sb'), basis=[(0.25, 0.25, 0.25), (0.0, 0.335, 0.158)], spacegroup=204, cellpar=[a, a, a, 90, 90, 90]) # Create a new atoms instance with Co at origo including all atoms on the # surface of the unit cell cosb3 = cut(skutterudite, origo=(0.25, 0.25, 0.25), extend=1.01) # Define the atomic bonds to show bondatoms = [] symbols = cosb3.get_chemical_symbols() for i in range(len(cosb3)): for j in range(i): if (symbols[i] == symbols[j] == 'Co' and cosb3.get_distance(i, j) < 4.53): bondatoms.append((i, j)) elif (symbols[i] == symbols[j] == 'Sb' and cosb3.get_distance(i, j) < 2.99): bondatoms.append((i, j)) # Create nice-looking image using povray io.write('spacegroup-cosb3.pov', cosb3, transparent=False, display=False, run_povray=True,
from ase.spacegroup import crystal a = 4.6 c = 2.95 rutile =crystal(['Ti', 'O'], basis=[(0, 0, 0), (0.3, 0.3, 0.0)], spacegroup=136, cellpar=[a, a, c, 90, 90, 90])
from ase.spacegroup import crystal a = 4.05 al = crystal('Al', [(0,0,0)], spacegroup=225, cellpar=[a, a, a, 90, 90, 90])
from ase.spacegroup import crystal a = 5.64 nacl = crystal(['Na', 'Cl'], [(0, 0, 0), (0.5, 0.5, 0.5)], spacegroup=225, cellpar=[a, a, a, 90, 90, 90])
def tags2atoms(tags, store_tags=False, primitive_cell=False, subtrans_included=True): """Returns an Atoms object from a cif tags dictionary. See read_cif() for a description of the arguments.""" if primitive_cell and subtrans_included: raise RuntimeError( 'Primitive cell cannot be determined when sublattice translations ' 'are included in the symmetry operations listed in the CIF file, ' 'i.e. when `subtrans_included` is True.') a = tags['_cell_length_a'] b = tags['_cell_length_b'] c = tags['_cell_length_c'] alpha = tags['_cell_angle_alpha'] beta = tags['_cell_angle_beta'] gamma = tags['_cell_angle_gamma'] scaled_positions = np.array([tags['_atom_site_fract_x'], tags['_atom_site_fract_y'], tags['_atom_site_fract_z']]).T symbols = [] if '_atom_site_type_symbol' in tags: labels = tags['_atom_site_type_symbol'] else: labels = tags['_atom_site_label'] for s in labels: # Strip off additional labeling on chemical symbols m = re.search(r'([A-Z][a-z]?)', s) symbol = m.group(0) symbols.append(symbol) # Symmetry specification, see # http://www.iucr.org/resources/cif/dictionaries/cif_sym for a # complete list of official keys. In addition we also try to # support some commonly used depricated notations no = None if '_space_group.it_number' in tags: no = tags['_space_group.it_number'] elif '_space_group_it_number' in tags: no = tags['_space_group_it_number'] elif '_symmetry_int_tables_number' in tags: no = tags['_symmetry_int_tables_number'] symbolHM = None if '_space_group.Patterson_name_h-m' in tags: symbolHM = tags['_space_group.patterson_name_h-m'] elif '_symmetry_space_group_name_h-m' in tags: symbolHM = tags['_symmetry_space_group_name_h-m'] elif '_space_group_name_h-m_alt' in tags: symbolHM = tags['_space_group_name_h-m_alt'] if symbolHM is not None: symbolHM = old_spacegroup_names.get(symbolHM.strip(), symbolHM) for name in ['_space_group_symop_operation_xyz', '_space_group_symop.operation_xyz', '_symmetry_equiv_pos_as_xyz']: if name in tags: sitesym = tags[name] break else: sitesym = None spacegroup = 1 if sitesym is not None: subtrans = [(0.0, 0.0, 0.0)] if subtrans_included else None spacegroup = spacegroup_from_data( no=no, symbol=symbolHM, sitesym=sitesym, subtrans=subtrans) elif no is not None: spacegroup = no elif symbolHM is not None: spacegroup = symbolHM else: spacegroup = 1 if store_tags: kwargs = {'info': tags.copy()} else: kwargs = {} if 'D' in symbols: deuterium = [symbol == 'D' for symbol in symbols] symbols = [symbol if symbol != 'D' else 'H' for symbol in symbols] else: deuterium = False atoms = crystal(symbols, basis=scaled_positions, cellpar=[a, b, c, alpha, beta, gamma], spacegroup=spacegroup, primitive_cell=primitive_cell, **kwargs) if deuterium: masses = atoms.get_masses() masses[atoms.numbers == 1] = 1.00783 masses[deuterium] = 2.01355 atoms.set_masses(masses) return atoms
from __future__ import print_function import unittest from ase.spacegroup import crystal import set_path from tilde.core.settings import settings from tilde.core.api import API from tilde.parsers import Output crystal_obj = crystal( ('Sr', 'Ti', 'O', 'O'), basis=[(0, 0.5, 0.25), (0, 0, 0), (0, 0, 0.25), (0.255, 0.755, 0)], spacegroup=140, cellpar=[5.511, 5.511, 7.796, 90, 90, 90], primitive_cell=True ) settings['skip_unfinished'], settings['skip_notenergy'] = False, False work = API(settings) virtual_calc = Output() # we always consider "calculation" while using tilde virtual_calc.structures = [ crystal_obj ] virtual_calc, error = work.classify(virtual_calc) if error: raise RuntimeError(error) virtual_calc = work.postprocess(virtual_calc) target_category_num = 4 # perovskite category, pre-defined in /init-data.sql is_perovskite = target_category_num in virtual_calc.info['tags']