def cell_translate(ase_atoms): """Create dummy atoms for cell images.""" cell = ase_atoms.cell atoms_ = Atoms('H') atoms_.cell = cell atoms_.set_scaled_positions([0.5, 0.5, 0.5]) return atoms_
def read_cml(fileobj): data = contract(json.load(fileobj)) atoms = Atoms() datoms = data['atoms'] atoms = Atoms(datoms['elements']['number']) if 'unitcell' in data: cell = data['unitcell'] a = cell['a'] b = cell['b'] c = cell['c'] alpha = cell['alpha'] beta = cell['beta'] gamma = cell['gamma'] atoms.cell = Cell.fromcellpar([a, b, c, alpha, beta, gamma]) atoms.pbc = True coords = contract(datoms['coords']) if '3d' in coords: positions = np.array(coords['3d']).reshape(len(atoms), 3) atoms.set_positions(positions) else: positions = np.array(coords['3dfractional']).reshape(len(atoms), 3) atoms.set_scaled_positions(positions) yield atoms
def make_periodic(atoms: Atoms, vacuum_buffer: float = 10) -> Atoms: """Make an atoms object periodic Required for fitting with ``fit_gap`` Args: atoms: Atoms object to be adjusted vacuum_buffer: Amount of space to buffer on either side of the molecule Returns: Atoms object made periodic """ # Give the cell periodic boundary conditions in each direction atoms.pbc = [True] * 3 # Compute the size of the cell in each direction mol_size = np.max(atoms.positions, axis=0) - np.min(atoms.positions, axis=0) # Give a cell that is big enough to have the desired buffer on each size atoms.cell = np.diag(mol_size + vacuum_buffer * 2) # Center the atoms in the middle of it atoms.center() return atoms
def ori_structure(self): lead1=self.lead1=graphene(dict(latx=1,laty=self.laty,latz=1)).lmp_structure() n=len(lead1) center=graphene(dict(latx=self.latx,laty=self.laty,latz=1)).lmp_structure() center.translate(lead1.cell[0]) lead2=lead1.copy() lead2.translate(lead1.cell[0]+center.cell[0]) atoms=Atoms() atoms.extend(lead1) atoms.extend(center) atoms.extend(lead2) atoms.cell=center.cell atoms.cell[0]=lead1.cell[0]+center.cell[0]+lead2.cell[0] lx=self.extent(atoms)[0] self.getScale(lx/2) self.center_box(atoms) self.writeatoms(atoms,'graphene') low=atoms.positions[:,0].min()+2 hi=atoms.positions[:,0].max()-2 self.leftgroup=np.arange(len(atoms),dtype='int')[:n]+1 self.rightgroup=np.arange(len(atoms),dtype='int')[-n:]+1 self.fmag=self.strain/float(len(self.leftgroup)) self.posleft=atoms.positions[self.leftgroup[0]-1].copy()+(50,50,50) self.posright=atoms.positions[self.rightgroup[0]-1].copy()+(50,50,50) self.posleft[0]*=10 self.posright[0]*=10 for atom in atoms: atom.position=self.trans(atom.position) atoms.center(vacuum=50) return atoms
def test_center_nonperiodic(): import numpy as np from ase import Atoms a = Atoms('H') a.center(about=[0., 0., 0.]) print(a.cell) print(a.positions) assert not a.cell.any() assert not a.positions.any() a.cell = [0., 2., 0.] a.center() print(a) print(a.positions) assert np.abs(a.positions - [[0., 1., 0.]]).max() < 1e-15 a.center(about=[0., -1., 1.]) print(a.positions) assert np.abs(a.positions - [[0., -1., 1.]]).max() < 1e-15 assert np.abs(a.cell - np.diag([0., 2., 0.])).max() < 1e-15 a.center(axis=2, vacuum=2.) print(a.positions) print(a.cell) assert np.abs(a.positions - [[0., -1., 2.]]).max() < 1e-15 assert np.abs(a.cell - np.diag([0., 2., 4.])).max() < 1e-15
def test_axis_layout(): system = Atoms('H') a = 3. system.cell = (a, a, a) system.pbc = 1 for axis in range(3): system.center() system.positions[0, axis] = 0.0 calc = Octopus(**getkwargs(label='ink-%s' % 'xyz'[axis], Output='density + potential + wfs')) system.set_calculator(calc) system.get_potential_energy() rho = calc.get_pseudo_density(pad=False) #for dim in rho.shape: # assert dim % 2 == 1, rho.shape maxpoint = np.unravel_index(rho.argmax(), rho.shape) print('axis=%d: %s/%s' % (axis, maxpoint, rho.shape)) expected_max = [dim // 2 for dim in rho.shape] expected_max[axis] = 0 assert maxpoint == tuple(expected_max), '%s vs %s' % (maxpoint, expected_max) errs = check_interface(calc) for err in errs: if err.code == 'not implemented': continue if err.methname == 'get_dipole_moment': assert isinstance(err.error, OctopusIOError) else: raise AssertionError(err.error)
def get_ase_atoms(self,bbox=None,**kwargs): '''Create an ASE atoms object. (cf. https://wiki.fysik.dtu.dk/ase/ase/atoms.html ) **Parameters:** bbox : list of floats (bbox=[xmin,xmax,ymin,ymax,zmin,zmax]), optional If not None, sets the unit cell to the grid boundaries and moves the molecule in its center. **Returns:** atoms : Atoms object See https://wiki.fysik.dtu.dk/ase/ase/atoms.html for details .. Note:: ASE has to be in the PYTHONPATH ''' from ase import Atoms from ase.units import Bohr atoms = Atoms("".join(self.geo_info[:,0]), positions=self.geo_spec*Bohr, **kwargs) if bbox is not None: if len(bbox) != 6: raise ValueError("bbox has to have 6 elements") bbox = numpy.array(bbox) atoms.translate(-bbox[::2]*Bohr) atoms.cell = numpy.eye(3) * (bbox[1::2] - bbox[::2])*Bohr return atoms
def read_dmol_incoor(filename, bohr=True): """ Reads an incoor file and returns an atoms object. Notes ----- If bohr is True then incoor is assumed to be in bohr and the data is rescaled to Angstrom. """ lines = open(filename, 'r').readlines() symbols = [] positions = [] for i, line in enumerate(lines): if line.startswith('$cell vectors'): cell = np.zeros((3, 3)) for j, line in enumerate(lines[i + 1:i + 4]): cell[j, :] = [float(fld) for fld in line.split()] if line.startswith('$coordinates'): j = i + 1 while True: if lines[j].startswith('$end'): break flds = lines[j].split() symbols.append(flds[0]) positions.append(flds[1:4]) j += 1 atoms = Atoms(symbols=symbols, positions=positions, cell=cell, pbc=True) if bohr: atoms.cell = atoms.cell * Bohr atoms.positions = atoms.positions * Bohr return atoms
def test_counterions(): """ Test AtomicCounterIon is force/energy consistent over PBCs and with cutoff """ import numpy as np from ase import Atoms from ase import units from ase.calculators.counterions import AtomicCounterIon as ACI sigma = 1.868 * (1.0 / 2.0)**(1.0 / 6.0) epsilon = 0.00277 * units.kcal / units.mol atoms = Atoms('3Na', positions=np.array([[0, 0, -2], [0, 0, 0], [0, 0, 2]])) atoms.cell = [10, 10, 10] atoms.pbc = True atoms.calc = ACI(1, epsilon, sigma, rc=4.5) points = np.arange(-15., 15., 0.2) for p in points: f = atoms.get_forces() fn = atoms.calc.calculate_numerical_forces(atoms, 1e-5) df = (f - fn) assert abs(df).max() < 1e-8
def read_xdatcar(filename, skip=0, every=1): f = open(filename, 'r') lines = f.readlines() f.close() lattice_constant = float(lines[1].strip()) cell = numpy.array([[float(x) * lattice_constant for x in lines[2].split()], [float(x) * lattice_constant for x in lines[3].split()], [float(x) * lattice_constant for x in lines[4].split()]]) elements = lines[5].split() natoms = [int(x) for x in lines[6].split()] nframes = (len(lines)-7)/(sum(natoms) + 1) trajectory = [] for i in range(skip, nframes, every): a = Atoms('H'*sum(natoms)) a.masses = [1.0] * len(a) a.set_chemical_symbols(''.join([n*e for (n, e) in zip(natoms, elements)])) a.cell = cell.copy() a.set_pbc((True, True, True)) j = 0 for N, e in zip(natoms, elements): for k in range(N): split = lines[8 + i * (sum(natoms) + 1) + j].split() a[j].position = [float(l) for l in split[0:3]] j += 1 a.positions = numpy.dot(a.positions, cell) trajectory.append(a) return trajectory
def build_system(self, name): if name in extra: mol = Atoms(*extra[name]) mol.cell = self.unit_cell mol.center() else: self.bond_length = bondlengths.get(name, None) mol = MoleculeTask.build_system(self, name) return mol
def make_ase(self, species, positions): """Create ase Atoms object.""" # Get the principal axes and realign the molecule along z-axis. positions = PCA(n_components=3).fit_transform(positions) atoms = Atoms(species, positions=positions, pbc=True) atoms.cell = np.ptp(atoms.positions, axis=0) + 10 atoms.center() return atoms
def pad_atoms(atoms: Atoms, margin: float, directions='xy', in_place=False): """ Repeat the atoms in x and y, retaining only the repeated atoms within the margin distance from the cell boundary. Parameters ---------- atoms: ASE Atoms object The atoms that should be padded. margin: float The padding margin. Returns ------- ASE Atoms object Padded atoms. """ if not is_cell_orthogonal(atoms): raise RuntimeError('The cell of the atoms must be orthogonal.') if not in_place: atoms = atoms.copy() old_cell = atoms.cell.copy() axes = [{'x': 0, 'y': 1, 'z': 2}[direction] for direction in directions] reps = [1, 1, 1] for axis in axes: reps[axis] = int(1 + 2 * np.ceil(margin / atoms.cell[axis, axis])) if any([rep > 1 for rep in reps]): atoms *= reps atoms.positions[:] -= np.diag(old_cell) * [rep // 2 for rep in reps] atoms.cell = old_cell # import matplotlib.pyplot as plt # from abtem import show_atoms # show_atoms(atoms, plane='xz') # plt.show() to_keep = np.ones(len(atoms), dtype=bool) for axis in axes: to_keep *= (atoms.positions[:, axis] > -margin) * ( atoms.positions[:, axis] < atoms.cell[axis, axis] + margin) atoms = atoms[to_keep] # for axis in axes: # left = atoms[atoms.positions[:, axis] < margin] # left.positions[:, axis] += atoms.cell[axis, axis] # right = atoms[(atoms.positions[:, axis] > atoms.cell[axis, axis] - margin) & # (atoms.positions[:, axis] < atoms.cell[axis, axis])] # right.positions[:, axis] -= atoms.cell[axis, axis] # atoms += left + right return atoms
def rotatedCrystal(V, size=(2, 2, 1), a=1.3968418, cType='gr'): """ Generates a triangular crystal lattice of the given size and rotates it so that the new unit vectors align with the columns of V. The positions are set so that the center atom is at the origin. Size is expected to be even in all directions. 'a' is the atomic distance between the atoms of the hexagonal lattice daul to this crystal. In other words, a*sqrt(3) is the lattice constant of the triangular lattice. The returned object is of ase.Atoms type """ if cType == 'gr': cr = GB.grapheneCrystal(1, 1, 'armChair').aseCrystal(ccBond=a) elif cType == 'tr': numbers = [6.0] cell = numpy.array([[a * (3.0**0.5), 0, 0], [0.5 * a * (3.0**0.5), 1.5 * a, 0], [0, 0, 10 * a]]) positions = numpy.array([[0, 0, 0]]) cr = ase.Atoms(numbers=numbers, positions=positions, cell=cell, pbc=[True, True, True]) elif cType == 'tr-or': numbers = [6.0, 6.0] cell = numpy.array([[a * (3.0**0.5), 0, 0], [0, 3.0 * a, 0], [0, 0, 10 * a]]) positions = numpy.array([[0, 0, 0], [0.5 * a * (3.0**0.5), 1.5 * a, 0]]) cr = ase.Atoms(numbers=numbers, positions=positions, cell=cell, pbc=[True, True, True]) # Repeating ix = numpy.indices(size, dtype=int).reshape(3, -1) tvecs = numpy.einsum('ki,kj', ix, cr.cell) rPos = numpy.ndarray((len(cr) * len(tvecs), 3)) for i in range(len(cr)): rPos[i * len(tvecs):(i + 1) * len(tvecs)] = tvecs + cr.positions[i] # New cell size for i in range(3): cr.cell[i] *= size[i] cr = Atoms(symbols=['C'] * len(rPos), positions=rPos, cell=cr.cell, pbc=[True, True, True]) center = numpy.sum(cr.cell, axis=0) * 0.5 cr.positions = cr.positions - center cr.cell = numpy.einsum('ik,jk', cr.cell, V) cr.positions = numpy.einsum('ik,jk', cr.positions, V) return cr
def pymol_2_ase(pymol): """Convert pymol object into ASE Atoms.""" asemol = Atoms() for atm in pymol.atoms: asemol.append(Atom(chemical_symbols[atm.atomicnum], atm.coords)) asemol.cell = np.amax(asemol.positions, axis=0) - np.amin( asemol.positions, axis=0) + [10] * 3 asemol.pbc = True asemol.center() return asemol
def _make_ase(self, species, positions, smiles): """Create ase Atoms object.""" # Get the principal axes and realign the molecule along z-axis. positions = PCA(n_components=3).fit_transform(positions) atoms = Atoms(species, positions=positions, pbc=True) atoms.cell = np.ptp(atoms.positions, axis=0) + 10 atoms.center() # We're attaching this info so that it # can be later stored as an extra on AiiDA Structure node. atoms.info["smiles"] = smiles return atoms
def __init__( self, n=6, parameters=DEFAULT, ): atoms = Atoms([]) C_C = 1.42 C_H = 1.09 main_element = 'C' saturate_element = 'H' vacuum = 10 m = 1 b = np.sqrt(3) * C_C / 4 zz_unit = Atoms(main_element + '2', pbc=(0, 1, 1), cell=[2 * vacuum, 3 * C_C / 2.0, b * 4]) zz_unit.positions = [[0, 0, 0], [0, C_C / 2.0, b * 2]] edge_index0 = np.arange(m) * 2 + 1 edge_index1 = (n - 1) * m * 2 + np.arange(m) * 2 for i in range(n): layer = zz_unit.repeat((1, 1, m)) layer.positions[:, 1] -= 3 * C_C / 2 * i if i % 2 == 1: layer.positions[:, 2] += 2 * b layer[-1].position[2] -= b * 4 * m atoms += layer H_atoms0 = Atoms(saturate_element + str(m)) H_atoms0.positions = atoms[edge_index0].positions H_atoms0.positions[:, 1] += C_H H_atoms1 = Atoms(saturate_element + str(m)) H_atoms1.positions = atoms[edge_index1].positions H_atoms1.positions[:, 1] -= C_H atoms += H_atoms0 + H_atoms1 atoms.cell = [2 * vacuum, n * 3 * C_C / 2 + 2 * vacuum, m * 4 * b] atoms.set_pbc([False, False, True]) center = atoms.positions.mean(axis=0) center[0] = 0 center[2] = 0 atoms.translate(-center) Crystal1D.__init__( self, atoms, parameters=parameters, )
def pybel2ase(mol): asemol = Atoms() species = [chemical_symbols[atm.atomicnum] for atm in mol.atoms] pos = np.asarray([atm.coords for atm in mol.atoms]) pca = PCA(n_components=3) posnew = pca.fit_transform(pos) #posnew[:,2]=0.0 atoms = Atoms(species, positions=posnew) sys_size = np.ptp(atoms.positions, axis=0) atoms.pbc = True atoms.cell = sys_size + 10 atoms.center() return atoms
def __init__( self, n=7, parameters=DEFAULT, ): atoms = Atoms([]) C_C = 1.42 C_H = 1.09 main_element = 'C' saturate_element = 'H' vacuum = 10 b = np.sqrt(3) * C_C / 4 arm_unit = Atoms(main_element + '2', pbc=(1, 0, 1), cell=[ [2 * vacuum, 0, 0 ], [0, 2 * b, 1.5*C_C], [0, 0, 3 * C_C ],]) arm_unit.positions = [[0, 0, -1.5*C_C], [0, 0, -0.5*C_C]] core_atoms = arm_unit.repeat((1, n, 1)) h_positions=np.array([ [0, -np.sqrt(3) / 2 * C_H, - C_H * 0.5], [0, -np.sqrt(3) / 2 * C_H, C_H * 0.5], ]) atoms = Atoms( saturate_element + '2', cell= core_atoms.get_cell(), ) atoms.positions = core_atoms[:2].positions + h_positions atoms += core_atoms last_hydrogens = Atoms( saturate_element + '2', ) h_positions[:, 1] *= -1 last_hydrogens.positions = core_atoms[-2:].positions + h_positions atoms += last_hydrogens atoms.cell = [b * 2 * n + 2 * vacuum, 2 * vacuum, 3 * C_C] atoms.set_pbc([False, False, True]) atoms.wrap() atoms.translate((0, -b*float(n-1), 0)) Crystal1D.__init__( self, atoms, parameters=parameters, )
def lmp_structure(self): atoms=Atoms() lead1=self.m.lmp_structure() self.hatom=len(lead1) lead2=lead1.copy() lead3=lead1.copy() atoms.extend(lead1) lead2.translate(lead1.cell[0]) atoms.extend(lead2) lead3.translate(lead1.cell[0]*2) atoms.extend(lead3) atoms.cell=lead1.cell.copy() atoms.cell[0]=lead1.cell[0]*3 atoms.center() return atoms
def pybel2ase(mol): """converts pybel molecule into ase Atoms""" asemol = Atoms() species = [chemical_symbols[atm.atomicnum] for atm in mol.atoms] pos = np.asarray([atm.coords for atm in mol.atoms]) pca = PCA(n_components=3) posnew = pca.fit_transform(pos) atoms = Atoms(species, positions=posnew) sys_size = np.ptp(atoms.positions, axis=0) atoms.rotate(-90, 'z') #cdxml are rotated atoms.pbc = True atoms.cell = sys_size + 10 atoms.center() return atoms
def read_con(filename): f = open(filename, 'r') lines = f.readlines() f.close() trajectory = [] line_index = 0 while True: try: boxlengths = numpy.array([float(length) for length in lines[line_index+2].split()[0:3]]) boxangles = numpy.array([float(angle) for angle in lines[line_index+3].split()[0:3]]) cell = length_angle_to_box(boxlengths, boxangles) num_types = int(lines[line_index+6].split()[0]) num_each_type = [int(n) for n in lines[line_index+7].split()[0:num_types]] mass_each_type = [float(n) for n in lines[line_index+8].split()[0:num_types]] a = Atoms('H'*sum(num_each_type)) a.cell = cell a.set_pbc((True, True, True)) frozen = [] positions = [] symbols = [] masses = [] line_index += 9 atom_index = 0 for i in range(num_types): symbol = lines[line_index].strip() mass = mass_each_type[i] line_index += 2 for j in range(num_each_type[i]): split = lines[line_index].split() positions.append([float(s) for s in split[0:3]]) symbols.append(symbol) masses.append(mass) if split[3] != '0': frozen.append(atom_index) atom_index += 1 line_index += 1 a.set_chemical_symbols(symbols) a.set_positions(positions) a.set_masses(masses) a.set_constraint(FixAtoms(frozen)) except: if len(trajectory) == 1: return trajectory[0] if len(trajectory) == 0: raise IOError, "Could not read con file." return trajectory trajectory.append(a)
def rdkit2ase(m): pos = m.GetConformer().GetPositions() natoms = m.GetNumAtoms() species = [m.GetAtomWithIdx(j).GetSymbol() for j in range(natoms)] #Get the principal axes and realign the molecule pca = PCA(n_components=3) pca.fit(pos) posnew = pca.transform(pos) #Set the z to 0.0 #posnew[:,2]=0.0 atoms = Atoms(species, positions=posnew) sys_size = np.ptp(atoms.positions, axis=0) atoms.pbc = True atoms.cell = sys_size + 10 atoms.center() return atoms
def slab(m, n): atoms = Atoms() for i in range(n): if i % 2 == 0: layer = ac_unit.repeat((m, 1, 1)) if i % 2 == 1: layer = ac_unit.repeat((m, 1, 1)) layer.positions[:, 0] += 3. / 2 * C_C if saturated: if i == 0: sat = ac_sat_unit.repeat((m, 1, 1)) sat.positions[:, 1] -= np.sqrt(3.) / 2 * C_H sat.positions[:, 0] -= 1. / 2 * C_H layer += sat elif i == n - 1: sat = ac_sat_unit.repeat((m, 1, 1)) sat.positions[:, 1] += np.sqrt(3.) / 2 * C_H sat.positions[:, 0] -= 1. / 2 * C_H - 3. / 2 * C_C * (i % 2) layer += sat layer.positions[:, 1] += b / 2 * i atoms += layer xmax = np.max(atoms.positions[:, 0]) for atom in atoms: if xmax - C_C / 2. < atom.position[0]: atom.position[0] -= m * 3 * C_C if saturated: xmax = np.max(atoms.positions[:, 0]) xmin = np.min(atoms.positions[:, 0]) for atom in atoms: posit = atom.position if xmax - C_C / 6. < posit[0] and atom.number == 6: h_posit = [posit[0] + C_H, posit[1], posit[2]] atoms += Atom('H', position=h_posit) if posit[0] < xmin + C_C / 6. and atom.number == 6: h_posit = [posit[0] - C_H, posit[1], posit[2]] atoms += Atom('H', position=h_posit) atoms.cell = [m * 3 * C_C, n * b / 2, 2 * vacuum] atoms.center() return atoms
def slab(m, n): atoms = Atoms() for i in range(n): if i % 2 == 0: layer = ac_unit.repeat((m, 1, 1)) if i % 2 == 1: layer = ac_unit.repeat((m, 1, 1)) layer.positions[:, 0] += 3./2 * C_C if saturated: if i == 0: sat = ac_sat_unit.repeat((m,1,1)) sat.positions[:,1] -= np.sqrt(3.) / 2 * C_H sat.positions[:,0] -= 1. / 2 * C_H layer += sat elif i == n - 1: sat = ac_sat_unit.repeat((m,1,1)) sat.positions[:,1] += np.sqrt(3.) / 2 * C_H sat.positions[:,0] -= 1. / 2 * C_H - 3./2 * C_C * (i % 2) layer += sat layer.positions[:, 1] += b / 2 * i atoms += layer xmax = np.max(atoms.positions[:,0]) for atom in atoms: if xmax - C_C/2. < atom.position[0]: atom.position[0] -= m*3*C_C if saturated: xmax = np.max(atoms.positions[:,0]) xmin = np.min(atoms.positions[:,0]) for atom in atoms: posit = atom.position if xmax - C_C/6. < posit[0] and atom.number == 6: h_posit = [posit[0] + C_H, posit[1], posit[2]] atoms += Atom('H', position = h_posit) if posit[0] < xmin + C_C/6. and atom.number == 6: h_posit = [posit[0] - C_H, posit[1], posit[2]] atoms += Atom('H', position = h_posit) atoms.cell = [m * 3 * C_C, n * b/2, 2 * vacuum] atoms.center() return atoms
def lmp_structure(self): atoms = Atoms() lead1 = self.m1.lmp_structure() center = self.m.lmp_structure() lead2 = self.m2.lmp_structure() atoms.extend(lead1) center.translate(lead1.cell[0]) atoms.extend(center) lead2.translate(lead1.cell[0] + center.cell[0]) atoms.extend(lead2) atoms.cell = lead1.cell.copy() #atoms.set_pbc([0,0,0]) atoms.cell[0] = lead1.cell[0] + center.cell[0] + lead2.cell[0] #atoms.center(10.0,axis=[1,2]) #atoms.center() x = atoms.positions[:, 0] return center
def test_kpts2kpts(lat): print() print(lat) bandpath = lat.bandpath() a = Atoms() a.cell = lat.tocell().complete() a.pbc[:lat.ndim] = True path = {'path': bandpath.path} bandpath2 = kpts2kpts(path, atoms=a) print('cell', a.cell) print('Original', bandpath) print('path', path) print('Produced by kpts2kpts', bandpath2) sp = set(bandpath.special_points) sp2 = set(bandpath2.special_points) msg = ('Input and output bandpath from kpts2kpts dont agree!\n' 'Input: {}\n Output: {}'.format(bandpath, bandpath2)) assert sp == sp2, msg
def lmp_structure(self): atoms=Atoms() lead1=self.m1.lmp_structure() center=self.m.lmp_structure() lead2=self.m2.lmp_structure() atoms.extend(lead1) center.translate(lead1.cell[0]) atoms.extend(center) lead2.translate(lead1.cell[0]+center.cell[0]) atoms.extend(lead2) atoms.cell=lead1.cell.copy() #atoms.set_pbc([0,0,0]) atoms.cell[0]=lead1.cell[0]+center.cell[0]+lead2.cell[0] #atoms.center(10.0,axis=[1,2]) #atoms.center() x=atoms.positions[:,0] return center
def test_properties(): charges = np.array([-1, 1]) a = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1.1)], charges=charges) a.pbc[0] = 1 assert a.pbc.any() assert not a.pbc.all() a.pbc = 1 assert a.pbc.all() a.cell = (1, 2, 3) a.cell *= 2 a.cell[0, 0] = 3 assert not (a.cell.diagonal() - (3, 4, 6)).any() assert (charges == a.get_initial_charges()).all() assert a.has('initial_charges') # XXX extend has to calculator properties assert not a.has('charges')
def organize(a): """this function receives an Atoms data structure (ASE libraries), organizes the atoms in it according to their atomic symbols, and returns another Atoms data structure which is organized""" symb = [] b = Atoms() b.cell = a.cell b.pbc = [True, True, True] for j in a: if str(j.symbol) not in symb: symb.append(str(j.symbol)) symb = sorted(symb) for i in symb: for j in a: if str(j.symbol) == i: b.append(j) return b
def rotatedCrystal(V, size=(2, 2, 1), a=1.3968418, cType='gr'): """ Generates a triangular crystal lattice of the given size and rotates it so that the new unit vectors align with the columns of V. The positions are set so that the center atom is at the origin. Size is expected to be even in all directions. 'a' is the atomic distance between the atoms of the hexagonal lattice daul to this crystal. In other words, a*sqrt(3) is the lattice constant of the triangular lattice. The returned object is of ase.Atoms type """ if cType == 'gr': cr = GB.grapheneCrystal(1, 1, 'armChair').aseCrystal(ccBond=a) elif cType == 'tr': numbers = [6.0] cell = numpy.array([[a * (3.0 ** 0.5), 0, 0], [0.5 * a * (3.0 ** 0.5), 1.5 * a, 0], [0, 0, 10 * a]]) positions = numpy.array([[0, 0, 0]]) cr = ase.Atoms(numbers=numbers, positions=positions, cell=cell, pbc=[True, True, True]) elif cType == 'tr-or': numbers = [6.0, 6.0] cell = numpy.array([[a * (3.0 ** 0.5), 0, 0], [0, 3.0 * a, 0], [0, 0, 10 * a]]) positions = numpy.array([[0, 0, 0], [0.5 * a * (3.0 ** 0.5), 1.5 * a, 0]]) cr = ase.Atoms(numbers=numbers, positions=positions, cell=cell, pbc=[True, True, True]) # Repeating ix = numpy.indices(size, dtype=int).reshape(3, -1) tvecs = numpy.einsum('ki,kj', ix, cr.cell) rPos = numpy.ndarray((len(cr) * len(tvecs), 3)) for i in range(len(cr)): rPos[i * len(tvecs):(i + 1) * len(tvecs)] = tvecs + cr.positions[i] # New cell size for i in range(3): cr.cell[i] *= size[i] cr = Atoms(symbols=['C'] * len(rPos), positions=rPos, cell=cr.cell, pbc=[True, True, True]) center = numpy.sum(cr.cell, axis=0) * 0.5 cr.positions = cr.positions - center cr.cell = numpy.einsum('ik,jk', cr.cell, V) cr.positions = numpy.einsum('ik,jk', cr.positions, V) return cr
def read_atoms_select(): ''' ''' from ase import Atoms, Atom atoms = Atoms() cell_vertexs = [] for obj in bpy.context.selected_objects: if "BOND" in obj.name.upper(): continue if obj.type not in {'MESH', 'SURFACE', 'META'}: continue name = "" if 'atom_kind_' == obj.name[0:10]: print(obj.name) ind = obj.name.index('atom_kind_') ele = obj.name[ind + 10:].split('_')[0] if len(obj.children) != 0: for vertex in obj.data.vertices: location = obj.matrix_world @ vertex.co atoms.append(Atom(ele, location)) else: if not obj.parent: location = obj.location atoms.append(Atom(ele, location)) # cell if 'point_cell' == obj.name[0:10]: print(obj.name) if len(obj.children) != 0: for vertex in obj.data.vertices: location = obj.matrix_world @ vertex.co # print(location) cell_vertexs.append(location) # print(atoms) # print(cell_vertexs) if cell_vertexs: cell = [cell_vertexs[4], cell_vertexs[2], cell_vertexs[1]] atoms.cell = cell atoms.pbc = [True, True, True] # self.atoms = atoms return atoms
def get_atomic_structure(xml): """ Parse atom. Parameters """ nat = xml.attrib['nat'] alat = xml.attrib['alat'] atoms = Atoms() positions = [] symbols = [] all_species = [] for item in xml.find('./atomic_positions'): species = item.attrib['name'] all_species.append(species) symbol = species.split('_')[0].split('-')[0] if len(symbol) == 3: symbol = symbol[0:2] symbols.append(symbol) index = item.attrib['index'] data = item.text.split() # These can be fractions and other expressions position = [float(data[0])*units['Bohr'], float(data[1])*units['Bohr'], float(data[2])*units['Bohr']] positions.append(position) positions = np.array(positions) # positions = positions**units['Bohr'] atoms = Atoms(symbols = symbols, positions = positions) atoms.arrays['species'] = all_species # cell cell = [] for item in xml.find('./cell'): data = item.text.split() cell.append([float(data[0]), float(data[1]), float(data[2])]) cell = np.array(cell) cell = cell*units['Bohr'] atoms.cell = cell atoms.pbc = True return atoms
def read_blase_collection(coll): ''' ''' atoms = Atoms() name = coll.name # atoms for obj in coll.children['%s_atoms' % name].all_objects: ele = obj.name.split('_')[2] if len(obj.children) != 0: for vertex in obj.data.vertices: location = obj.matrix_world @ vertex.co atoms.append(Atom(symbol=ele, position=location)) else: if not obj.parent: location = obj.location atoms.append(Atom(ele, location)) # atoms properties scale = {} for obj in coll.children['%s_instancers' % name].all_objects: ele = obj.name.split('_')[3] scale[ele] = obj.scale # cell coll_cell = coll.children['%s_cell' % name] cell_vertexs = [] if 'point_cell' in coll_cell.all_objects.keys(): obj = coll_cell.all_objects['point_cell'] for vertex in obj.data.vertices: location = obj.matrix_world @ vertex.co cell_vertexs.append(location) if cell_vertexs: cell = [cell_vertexs[4], cell_vertexs[2], cell_vertexs[1]] atoms.cell = cell atoms.pbc = coll.blase.pbc # coll property # self.atoms = atoms batoms = Batoms(atoms, name=name, coll=coll, scale=scale) return batoms
def export_blase(): ''' ''' atoms = Atoms() cell_vertexs = [] for obj in bpy.context.selected_objects: if "BOND" in obj.name.upper(): continue if obj.type not in {'MESH', 'SURFACE', 'META'}: continue name = "" if 'atom_kind' in obj.name: print(obj.name) ele = obj.name[10:].split('.')[0] if len(obj.children) != 0: for vertex in obj.data.vertices: location = obj.matrix_world @ vertex.co atoms.append(Atom(ele, location)) else: if not obj.parent: location = obj.location atoms.append(Atom(ele, location)) # cell if 'point_cell' in obj.name: print(obj.name) if len(obj.children) != 0: for vertex in obj.data.vertices: location = obj.matrix_world @ vertex.co # print(location) cell_vertexs.append(location) # print(atoms) # print(cell_vertexs) if cell_vertexs: cell = [cell_vertexs[4], cell_vertexs[2], cell_vertexs[1]] atoms.cell = cell return atoms
def ori_structure(self): lead1 = self.lead1 = graphene(dict(latx=1, laty=self.laty, latz=1)).lmp_structure() n = len(lead1) center = graphene(dict(latx=self.latx, laty=self.laty, latz=1)).lmp_structure() center.translate(lead1.cell[0]) lead2 = lead1.copy() lead2.translate(lead1.cell[0] + center.cell[0]) atoms = Atoms() atoms.extend(lead1) atoms.extend(center) atoms.extend(lead2) atoms.cell = center.cell atoms.cell[0] = lead1.cell[0] + center.cell[0] + lead2.cell[0] lx = self.extent(atoms)[0] self.getScale(lx / 2) self.center_box(atoms) self.writeatoms(atoms, 'graphene') low = atoms.positions[:, 0].min() + 2 hi = atoms.positions[:, 0].max() - 2 self.leftgroup = np.arange(len(atoms), dtype='int')[:n] + 1 self.rightgroup = np.arange(len(atoms), dtype='int')[-n:] + 1 self.fmag = self.strain / float(len(self.leftgroup)) self.posleft = atoms.positions[self.leftgroup[0] - 1].copy() + (50, 50, 50) self.posright = atoms.positions[self.rightgroup[0] - 1].copy() + (50, 50, 50) self.posleft[0] *= 10 self.posright[0] *= 10 for atom in atoms: atom.position = self.trans(atom.position) atoms.center(vacuum=50) return atoms
return atoms[indices] def findele(atoms, ele): tags = atoms.get_chemical_symbols() mask = [i for i, tag in enumerate(tags) if tag==ele] return mask # read CONTCAR a = 15.865/4 xyz = a/2 #atoms = read('~/xcp2k/bulks/pt-relax/relax/') bulk = Atoms([Atom('Pt', (0.0, 0.0, 0.0)), Atom('Pt', (xyz, xyz, 0.0)), Atom('Pt', (xyz, 0.0, xyz)), Atom('Pt', (0.0, xyz, xyz))]) bulk.cell= a * np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]) atoms = surface(bulk, (1, 1, 1), 4, vacuum=0.0) atoms.pbc = [True, True, True] constraint = FixAtoms(mask=[atom.position[2] < 3 for atom in atoms]) atoms.set_constraint(constraint) atoms.cell[2][2] = 25 atoms = sortz(atoms) #### ads = Atoms('CO') ads[0].position = atoms[-1].position ads[1].position = atoms[-1].position ads[0].z = ads[0].z + 1.80
def kwargs2atoms(kwargs): """Extract atoms object from keywords and return remaining keywords.""" kwargs = purify(kwargs) coord_keywords = ['coordinates', 'xyzcoordinates', 'pdbcoordinates', 'reducedcoordinates', 'xsfcoordinates', 'xsfcoordinatesanimstep'] nkeywords = 0 for keyword in coord_keywords: if keyword in kwargs: nkeywords += 1 if nkeywords == 0: raise OctopusParseError('No coordinates') elif nkeywords > 1: raise OctopusParseError('Multiple coordinate specifications present. ' 'This may be okay in Octopus, but we do not ' 'implement it.') def get_positions_from_block(keyword): # %Coordinates or %ReducedCoordinates -> atomic numbers, positions. block = kwargs.pop(keyword) positions = [] numbers = [] for row in block: assert len(row) in [ndims + 1, ndims + 2] row = row[:ndims + 1] sym = row[0] assert sym.startswith("'") and sym.endswith("'") sym = sym[1:-1] pos0 = np.zeros(3) ndim = kwargs.get('dimensions', 3) pos0[:ndim] = map(float, row[1:]) number = atomic_numbers[sym] # Use 0 ~ 'X' for unknown? numbers.append(number) positions.append(pos0) positions = np.array(positions) return numbers, positions def read_atoms_from_file(keyword): if keyword not in kwargs: return None fname = kwargs.pop(keyword) fmt = keyword[:3].lower() read_method = {'xyz': read_xyz, 'pdb': read_pdb, 'xsf': read_xsf}[fmt] # XXX test xyz, pbd and xsf if fmt == 'xsf' and 'xsfcoordinatesanimstep' in kwargs: anim_step = kwargs.pop('xsfcoordinatesanimstep') slice = slice(anim_step, anim_step + 1, 1) # XXX test animstep images = read_method(fname, slice(None, None, 1)) if len(images) != 1: raise OctopusParseError('Expected only one image. Don\'t know ' 'what to do with %d images.' % len(images)) return images[0] ndims = kwargs.get('dimensions', 3) cell, kwargs = kwargs2cell(kwargs) # XXX fix interaction between pbc and possibly existing pbc in XSF/etc. # XXX remember to pop atoms = None if 'coordinates' in kwargs: numbers, positions = get_positions_from_block('coordinates') atoms = Atoms(numbers=numbers, positions=positions) elif 'reducedcoordinates' in kwargs: numbers, rpositions = get_positions_from_block('reducedcoordinates') atoms = Atoms(numbers=numbers, scaled_positions=rpositions) else: for keyword in ['xyzcoordinates', 'pdbcoordinates', 'xsfcoordinates']: atoms = read_atoms_from_file(keyword) if atoms is not None: break else: raise OctopusParseError('Apparently there are no atoms.') assert atoms is not None # Either we have non-periodic BCs or the atoms object already # got its BCs from reading the file. In the latter case # we shall override only if PeriodicDimensions was given specifically: pdims = kwargs.pop('periodicdimensions', None) if pdims is not None: pbc = np.zeros(3, dtype=bool) pdims = int(pdims) pbc[:pdims] = True atoms.pbc = pbc if cell is not None: atoms.cell = cell return atoms, kwargs
from ase import Atoms a = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1.1)]) a.pbc[0] = 1 assert a.pbc.any() assert not a.pbc.all() a.pbc = 1 assert a.pbc.all() a.cell = (1, 2, 3) a.cell *= 2 a.cell[0, 0] = 3 assert not (a.cell.diagonal() - (3, 4, 6)).any()
def convert_to_ase(sys, species=None): """ Convert a given pyscal structure to ase object Parameters ---------- sys : System object the system object to be converted species : list of str a list of species in the system Returns ------- aseobject: ASE atoms object Notes ----- ASE needs the species of atoms. If a property called `species` exist in :attr:`~pyscal.catom.Atom.custom`, this value is used for species. However if the value is not present, the keyword `species` is required. This should contain a mapping between :attr:`~pyscal.catom.Atom.type` and species name. For example, if `species` is `['Au', 'Ge']`, all atoms of type 1 are assigned as Au and those of type 2 are assigned as Ge. Note that ase is required to run this method. """ #we only do a local import of ASE, this is not super nice #we can change this later depending on if ASE is to be treated #as a full dependency atoms = sys.atoms #get element strings if 'species' not in atoms[0].custom.keys(): if species is None: raise ValueError( "Species was not known! To convert to ase, species need to be provided using the species keyword" ) #otherwise we know the species types = [atom.type for atom in atoms] unique_types = np.unique(types) if not (len(unique_types) == len(species)): raise ValueError( "Length of species and number of types found in system are different" ) #now assign the species to custom for atom in atoms: custom = atom.custom custom['species'] = species[int(atom.type - 1)] #we should also get the unique species key specieskey = "".join(species) else: #now if species are already there in custom #we can safely ignore any input types = [atom.type for atom in atoms] unique_types = np.unique(types) #now we know how many types are there species = [] for ut in unique_types: for atom in atoms: if ut == atom.type: species.append(atom.custom['species']) break specieskey = "".join(species) cell = sys.get_boxvecs() pbc = [1, 1, 1] #create ASE Atoms and assign everything aseobject = Atoms() aseobject.cell = cell aseobject.pbc = pbc #thats everything pretty much #now create ase Atom for atom in atoms: aseatom = Atom(atom.custom['species'], atom.pos) aseobject.append(aseatom) #done return aseobject
from ase.build import molecule a = 5.64 # Lattice constant for NaCl cell = [a / np.sqrt(2), a / np.sqrt(2), a] atoms = Atoms(symbols='Na2Cl2', pbc=True, cell=cell, scaled_positions=[(.0, .0, .0), (.5, .5, .5), (.5, .5, .0), (.0, .0, .5)]) * (3, 4, 2) + molecule('C6H6') # Move molecule to 3.5Ang from surface, and translate one unit cell in xy atoms.positions[-12:, 2] += atoms.positions[:-12, 2].max() + 3.5 atoms.positions[-12:, :2] += cell[:2] # Mark a single unit cell atoms.cell = cell # View used to start ag, and find desired viewing angle # view(atoms) rot = '35x,63y,36z' # found using ag: 'view -> rotate' # Common kwargs for eps, png, pov generic_projection_settings = { 'rotation': rot, # text string with rotation (default='' ) 'radii': .85, # float, or a list with one float per atom 'colors': None, # List: one (r, g, b) tuple per atom 'show_unit_cell': 2, # 0, 1, or 2 to not show, show, and show all of cell } # Extra kwargs only available for povray (All units in angstrom) povray_settings = {
def graphene_nanoribbon2(length, width, edge_type='zz', saturated=False, C_H=1.09, C_C=1.42, vacuum=2.5, magnetic=None, initial_mag=1.12, sheet=False, main_element='C', saturate_element='H'): """Create a graphene nanoribbon. Creates a graphene nanoribbon in the x-z plane, with the nanoribbon running along the z axis. Parameters: n: int The width of the nanoribbon. m: int The length of the nanoribbon. type: str The orientation of the ribbon. Must be either 'zigzag' or 'armchair'. saturated: bool If true, hydrogen atoms are placed along the edge. C_H: float Carbon-hydrogen bond length. Default: 1.09 Angstrom. C_C: float Carbon-carbon bond length. Default: 1.42 Angstrom. vacuum: float Amount of vacuum added to both sides. Default 2.5 Angstrom. magnetic: bool Make the edges magnetic. initial_mag: float Magnitude of magnetic moment if magnetic=True. sheet: bool If true, make an infinite sheet instead of a ribbon. """ b = np.sqrt(3) * C_C ac_unit = Atoms(main_element + '2', pbc=(1, 1, 0), cell=[3 * C_C, b, 2 * vacuum]) ac_unit.positions = [[0, 0, 0], [C_C, 0., 0.]] ac_sat_unit= Atoms(saturate_element + '2', pbc=(1, 1, 0), cell=[3 * C_C, b, 2 * vacuum]) ac_sat_unit.positions = [[0, 0, 0], [C_C + C_H, 0, 0]] def slab(m, n): atoms = Atoms() for i in range(n): if i % 2 == 0: layer = ac_unit.repeat((m, 1, 1)) if i % 2 == 1: layer = ac_unit.repeat((m, 1, 1)) layer.positions[:, 0] += 3./2 * C_C if saturated: if i == 0: sat = ac_sat_unit.repeat((m,1,1)) sat.positions[:,1] -= np.sqrt(3.) / 2 * C_H sat.positions[:,0] -= 1. / 2 * C_H layer += sat elif i == n - 1: sat = ac_sat_unit.repeat((m,1,1)) sat.positions[:,1] += np.sqrt(3.) / 2 * C_H sat.positions[:,0] -= 1. / 2 * C_H - 3./2 * C_C * (i % 2) layer += sat layer.positions[:, 1] += b / 2 * i atoms += layer xmax = np.max(atoms.positions[:,0]) for atom in atoms: if xmax - C_C/2. < atom.position[0]: atom.position[0] -= m*3*C_C if saturated: xmax = np.max(atoms.positions[:,0]) xmin = np.min(atoms.positions[:,0]) for atom in atoms: posit = atom.position if xmax - C_C/6. < posit[0] and atom.number == 6: h_posit = [posit[0] + C_H, posit[1], posit[2]] atoms += Atom('H', position = h_posit) if posit[0] < xmin + C_C/6. and atom.number == 6: h_posit = [posit[0] - C_H, posit[1], posit[2]] atoms += Atom('H', position = h_posit) atoms.cell = [m * 3 * C_C, n * b/2, 2 * vacuum] atoms.center() return atoms if edge_type == 'ac': return slab(length, width) elif edge_type == 'zz': atoms = slab(width / 2 + width % 2, length) atoms.rotate('-z', np.pi / 2, rotate_cell = False) atoms.cell = [length* b/2 , (width / 2 + width % 2) * 3 * C_C , 2 * vacuum] atoms.center() if width % 2 == 1: atoms_new = Atoms() cell = [length* b/2 , (width / 2 + .5) * 3 * C_C , 2 * vacuum] ymax = atoms.get_cell()[1,1] for atom in atoms: if atom.position[1] < ymax - C_C * 3. / 2: atoms_new += atom else: if atom.number == 1 and cell[1] < atom.position[1] - C_C * 3. / 2: if cell[0] < atom.position[0] + b / 2: atom.position[0] += b / 2 - cell[0] else: atom.position[0] += b / 2 atom.position[1] -= C_C * 3. / 2 atoms_new += atom atoms_new.cell = cell return atoms_new return atoms
(0.0000, 0.0000, -1.1560)]), 'Be2': ('Be2', [(0.0000, 0.0000, 0.0000), (0.0000, 0.0000, 2.460)])} c = ase.db.connect('results.db') for name in ex_atomization.keys() + 'H Li Be B C N O F Cl P'.split(): id = c.reserve(name=name) if id is None: continue if name in extra: a = Atoms(*extra[name]) else: a = molecule(name) if name in bondlengths: a.set_distance(0, 1, bondlengths[name]) a.cell = [11, 12, 13] a.center() a.calc = GPAW(xc='PBE', mode=PW(500), txt=name + '.txt', dtype=complex) a.get_potential_energy() exx = EXX(a.calc) exx.calculate() eexx = exx.get_total_energy() c.write(a, name=name, exx=eexx) del c[id]
import numpy as np from ase import Atoms a = Atoms('H') a.center(about=[0., 0., 0.]) print(a.cell) print(a.positions) assert not a.cell.any() assert not a.positions.any() a.cell = [0., 2., 0.] a.center() print(a) print(a.positions) assert np.abs(a.positions - [[0., 1., 0.]]).max() < 1e-15 a.center(about=[0., -1., 1.]) print(a.positions) assert np.abs(a.positions - [[0., -1., 1.]]).max() < 1e-15 assert np.abs(a.cell - np.diag([0., 2., 0.])).max() < 1e-15 a.center(axis=2, vacuum=2.) print(a.positions) print(a.cell) assert np.abs(a.positions - [[0., -1., 2.]]).max() < 1e-15 assert np.abs(a.cell - np.diag([0., 2., 4.])).max() < 1e-15
def read_ion(fileobj, recover_indices=True, recover_constraints=True): text = fileobj.read() comments_removed = [] comments = [] label = fileobj.name.split('.ion')[0] for line in text.splitlines(): # break into lines # remove and store the comments entry = line.split('#') if not entry[0]: pass else: comments_removed.append(entry[0].strip()) try: comments.append(line.split('#')[1]) except: pass atoms = Atoms() ################################## # Parse the unit cell ################################## """ because the unit cell is not included in the .ion atomic positions file in SPARC, this interface writes the information into the comments of .ion files. If a .inpt file is present this code will read that if it is not it will attempt to read the comments to find that information. The logic for doing this is quite complicated (as seen below) """ inpt_file_usable = True lat_vec_speficied = False comments_bad = False lat_array = [] # Loop to read cell/latvec from either .inpt or the comment # this is pretty complicated while True: # try to get the unit cell from the .inpt file in the same directory if label + '.inpt' in os.listdir('.') and inpt_file_usable == True: with open(label + '.inpt', 'r') as f: input_file = f.read() if 'CELL' not in input_file: # We can't find the CELL in the input file # set the flag to false and re-run the while loop. inpt_file_usable = False del input_file continue input_file = input_file.split('\n') for line in input_file: if 'CELL' in line: # find the line with the cell info cell = line.strip().split()[1:] cell = np.array([float(a) for a in cell]) if 'LATVEC' in line: # get lattice vectors from next 3 lines lat_vec_speficied = True index = input_file.index(line) for lat_vec in [input_file[a] for a in range(index + 1, index + 4)]: vec = lat_vec.strip().split() vec = np.array([float(a) for a in vec]) lat_array.append( vec / np.linalg.norm(vec)) # normalize lat_array = np.array(lat_array) if lat_vec_speficied == False: lat_array = np.eye(3) if 'cell' in locals() and 'lat_array' in locals(): atoms.cell = (lat_array.T * cell).T * Bohr break # we got the cell, leave the while loop else: inpt_file_usable = False del input_file continue # if the input file isn't usable, check the comments of the .ion file elif comments != [] and comments_bad == False: if 'CELL' in comments[1]: # Check only the second line for a CELL cell = np.empty((3, 3)) try: cell = comments[1].strip().split()[1:] cell = [float(a) for a in cell] for lat_vec in comments[3:6]: # check only these lines vec = lat_vec.strip().split() vec = np.array([float(a) for a in vec]) lat_array.append( vec / np.linalg.norm(vec)) # normalize lat_array = np.array(lat_array) atoms.cell = (lat_array.T * cell).T * Bohr break except: comments_bad = True else: # if getting it from the comments fails, return 0 unit cell warnings.warn('No lattice vectors were found in either the .inpt' ' file or in the comments of the .ion file. Thus no' ' unit cell was set for the resulting atoms object. ' 'Use the output atoms at your own risk') atoms.cell = np.zeros((3, 3)) break else: # if there is no cell in the .inpt file, and the .ion file, return 0 unit cell warnings.warn('No lattice vectors were found in either the .inpt file ' 'or in the comments of the .ion file. Thus no unit cell ' 'was set for the resulting atoms object. Use the output ' 'atoms at your own risk') atoms.cell = np.zeros((3, 3)) break ############################################ # parse the atoms ############################################ # parse apart the comments to try to recover the indices and boundary conditions """ The strategy of this code is to get the input text separated from the comments. The comments are then used to glean the information that is normally stored in the .inpt file, as well as the original indices of the atoms if this file was made by this wrapper. from there figure out where the different "Atom Type" blocks are located in the full text with the comments removed. Once that has been found parse these sections to gain recover the atomic positions and elemental identies of these "atom types." We also need to find the locations of the "RELAX" blocks that contain the information on which atoms are constained in each "Atom Type" block. """ indices_from_comments = [] constraints = [] spins = [] for comment in comments: if 'index' in comment: if len(comment.split()) == 2: try: index = int(comment.split()[1]) indices_from_comments.append(index) except: pass if 'PBC:' in comment: pbc_list = [] pbc = comment.split()[1:] for c in pbc: if c == 'True' or c == 'true': pbc_list.append(True) else: pbc_list.append(False) atoms.set_pbc(pbc_list) del pbc_list, pbc # find the index of line for all the different atom types atom_types = [i for i, x in enumerate( comments_removed) if 'ATOM_TYPE:' in x] relax_blocks = [i for i, x in enumerate(comments_removed) if 'RELAX:' in x] spin_blocks = [i for i, x in enumerate(comments_removed) if 'SPIN:' in x] for i, atom_type in enumerate(atom_types): type_dict = {} if i == len(atom_types) - 1: # treat the last block differently # Get the slice of text associated with this atom type type_slice = comments_removed[atom_types[i]:] # figure out if there are constraints after this block if recover_constraints: relax_block_index = [a for a in relax_blocks if a > atom_type] spin_block_index = [a for a in spin_blocks if a > atom_type] else: # Get the slice of text associated with this atom type type_slice = comments_removed[atom_types[i]: atom_types[i+1]] [a for a in relax_blocks if a > atom_type] # figure out if there are constraints after this block. # the constraint index will be sandwiched between the indicies # the current block and the next block if recover_constraints: relax_block_index = [ a for a in relax_blocks if a > atom_types[i]] relax_block_index = [ a for a in relax_block_index if a < atom_types[i+1]] spin_block_index = [a for a in spin_blocks if a > atom_types[i]] spin_block_index = [ a for a in spin_block_index if a < atom_types[i+1]] # extract informaton about the atom type from the section header for info in ['PSEUDO_POT', 'ATOM_TYPE', 'ATOMIC_MASS', 'COORD', 'N_TYPE_ATOM']: for line in type_slice[:15]: # narrow the search for speed if info in line: if 'COORD' in line: if 'FRAC' in line: type_dict['COORD_FRAC'] = 1 else: type_dict['COORD'] = 1 elif 'COORD' not in line: type_dict[info] = line.split()[1] # get the lines that contain the constraints block if recover_constraints: if len(relax_block_index) == 0: pass elif len(relax_block_index) == 1: # offest by one line relax_block_index = relax_block_index[0] + 1 relax_block_end = relax_block_index + \ int(type_dict['N_TYPE_ATOM']) relax_slice = comments_removed[relax_block_index: relax_block_end] elif len(relax_block_index) > 1: raise Exception('There appear to be multiple blocks of' ' constraints in one or more of the atom' ' types in your .ion file. Please inspect' ' it to repair it or pass in ' '`recover_constraints = False` to ingore' ' constraints') # the same as the code above, but for spin if len(spin_block_index) == 0: pass elif len(spin_block_index) == 1: spin_block_index = spin_block_index[0] + 1 # offest by one line spin_block_end = spin_block_index + int(type_dict['N_TYPE_ATOM']) spin_slice = comments_removed[spin_block_index: spin_block_end] elif len(spin_block_index) > 1: raise Exception('There appear to be multiple blocks of' ' spin values in one or more of the atom' ' types in your .ion file. Please inspect' ' it to repair it or pass in') # now parse out the atomic positions for coord_set in type_slice[len(type_dict):int(type_dict['N_TYPE_ATOM']) + len(type_dict)]: if 'COORD_FRAC' in type_dict.keys(): x1, x2, x3 = [float(a) for a in coord_set.split()[:3]] x, y, z = sum( [x * a for x, a in zip([x1, x2, x3], atoms.cell)]) elif 'COORD' in type_dict.keys(): x, y, z = [float(a) * Bohr for a in coord_set.split()[:3]] atoms += Atom(symbol=type_dict['ATOM_TYPE'], position=(x, y, z)) # get the constraints if recover_constraints: if 'relax_slice' in locals(): for cons_set in relax_slice: constraints.append([int(a) for a in cons_set.split()]) del relax_slice else: # there aren't constraints with this block, put in empty lists constraints += [[]] * int(type_dict['N_TYPE_ATOM']) if 'spin_slice' in locals(): for init_spin in spin_slice: spins.append(float(init_spin)) del spin_slice else: # there aren't spins with this block, put in zeros spins += [0] * int(type_dict['N_TYPE_ATOM']) # check if we can reorganize the indices if len(indices_from_comments) == len(atoms) and recover_indices: new_atoms = Atoms(['X'] * len(atoms), positions=[(0, 0, 0)] * len(atoms)) new_atoms.set_cell(atoms.cell) new_spins = [None] * len(atoms) # reassign indicies for old_index, new_index in enumerate(indices_from_comments): new_atoms[new_index].symbol = atoms[old_index].symbol new_atoms[new_index].position = atoms[old_index].position new_atoms.pbc = atoms.pbc new_spins[new_index] = spins[old_index] assert new_atoms.get_chemical_formula() == atoms.get_chemical_formula() atoms = new_atoms spins = new_spins # reorganize the constraints now if recover_constraints: new_constraints = [0] * len(atoms) for old_index, new_index in enumerate(indices_from_comments): new_constraints[new_index] = constraints[old_index] constraints = new_constraints atoms.set_initial_magnetic_moments(spins) # add constraints if recover_constraints: constraints = decipher_constraints(constraints) atoms.set_constraint(constraints) return atoms
from ase.build import molecule a = 5.64 # Lattice constant for NaCl cell = [a / np.sqrt(2), a / np.sqrt(2), a] atoms = Atoms(symbols='Na2Cl2', pbc=True, cell=cell, scaled_positions=[(.0, .0, .0), (.5, .5, .5), (.5, .5, .0), (.0, .0, .5)]) * (3, 4, 2) + molecule('C6H6') # Move molecule to 3.5Ang from surface, and translate one unit cell in xy atoms.positions[-12:, 2] += atoms.positions[:-12, 2].max() + 3.5 atoms.positions[-12:, :2] += cell[:2] # Mark a single unit cell atoms.cell = cell # View used to start ag, and find desired viewing angle #view(atoms) rot = '35x,63y,36z' # found using ag: 'view -> rotate' # Common kwargs for eps, png, pov kwargs = { 'rotation' : rot, # text string with rotation (default='' ) 'radii' : .85, # float, or a list with one float per atom 'colors' : None,# List: one (r, g, b) tuple per atom 'show_unit_cell': 2, # 0, 1, or 2 to not show, show, and show all of cell } # Extra kwargs only available for povray (All units in angstrom) kwargs.update({