def read_labeled_xyz(self, fileobj, map={}): """Read xyz like file with labeled atoms.""" if isinstance(fileobj, str): fileobj = open(fileobj) translate = dict(OPLSStructure.default_map.items() + map.items()) lines = fileobj.readlines() L1 = lines[0].split() if len(L1) == 1: del lines[:2] natoms = int(L1[0]) else: natoms = len(lines) types = [] types_map = {} for line in lines[:natoms]: symbol, x, y, z = line.split()[:4] element, label = self.split_symbol(symbol, translate) if symbol not in types: types_map[symbol] = len(types) types.append(symbol) self.append( Atom(element, [float(x), float(y), float(z)], tag=types_map[symbol])) self.types = types
def add_atom_on_surfaces(surface,element="H", zmax=None, zmin= None, minimum_distance=0.7, maximum_distance=1.4,max_trials=200): """ This function will add an atom (specified by element) on a surface. Z axis must be perpendicular to x,y plane. :param surface: ase.atoms.Atoms object :param element: element to be added :param zmin and zmax: z_range, cartesian coordinates :param minimum_distance: to ensure a good structure returned :param maximum_distance: to ensure a good structure returned :param max_trials: maximum nuber of trials :return: atoms objects """ cell=surface.get_cell() if np.power(cell[0:2, 2],2).sum() > 1.0e-6: raise RuntimeError("Currently, we only support orthorhombic cells") inspector=CheckAtoms(min_bond=minimum_distance,max_bond=maximum_distance) for _ in range(max_trials): x=np.random.uniform(low=0.0,high=cell[0][0]) y=np.random.uniform(low=0.0,high=cell[1][1]) z=np.random.uniform(low=zmin,high=zmax) t=surface.copy() t.append(Atom(symbol=element,position=[x,y,z],tag=1)) if inspector.is_good(t, quickanswer=True): return t raise NoReasonableStructureFound("No good structure found at function add_atom_on_surfaces")
def main(): args = sys.argv imgs = read(args[1], index="::40") #layers = find_layers(atoms.copy()) traj = Trajectory('traj.traj','w') H_indices = random.sample([a.index for a in imgs[0] if a.symbol == 'H'],8) n_img = 0 for atoms in imgs: nl=NeighborList([2.5/2]*len(atoms), self_interaction=False, bothways=True) nl.update(atoms) pair_selected = [] for H_index in H_indices: nl_indices, nl_offsets = nl.get_neighbors(H_index) pair_selected.append([H_index, random.sample(nl_indices, 1)[0]]) for HPd_dist in [1.0, 1.1, 1.2, 1.3, 1.4]: img = atoms.copy() for pair in pair_selected: H_index = pair[0] Pd_selected = pair[1] v = atoms[H_index].position - atoms[Pd_selected].position vn = v/np.linalg.norm(v) del img[H_index] img.append(Atom('H',atoms[Pd_selected].position + vn * HPd_dist)) traj.write(img) print n_img n_img+=1
def read_gaussian(filename): """Reads a Gaussian input file""" f = open(filename, 'r') lines = f.readlines() f.close() atoms = Atoms() for n, line in enumerate(lines): if ('#' in line): i = 0 while (lines[n + i + 5] != '\n'): info = lines[n + i + 5].split() if "Fragment" in info[0]: info[0] = info[0].replace("(", " ") info[0] = info[0].replace("=", " ") info[0] = info[0].replace(")", " ") fragment_line = info[0].split() symbol = fragment_line[0] tag = int(fragment_line[2]) - 1 else: symbol = info[0] tag = 0 position = [float(info[1]), float(info[2]), float(info[3])] atoms += Atom(symbol, position=position, tag=tag) i += 1 return atoms
def read_structures(self, content=None): """Read Structures from file and wirte them to self.structures""" from ase.atoms import Atoms from ase.atom import Atom images = [] temp_items = content.split('Standard orientation')[1:] for item_i in temp_items: lines = [line for line in item_i.split('\n') if len(line) > 0] #first 5 lines are headers del lines[:5] images.append(Atoms()) for line in lines: #if only - in line it is the end if set(line).issubset(set('- ')): break tmp_line = line.strip().split() if not len(tmp_line) == 6: raise RuntimeError( 'Length of line does not match structure!') #read atom try: atN = int(tmp_line[1]) pos = tuple(float(x) for x in tmp_line[3:]) except ValueError: raise ValueError( 'Expected a line with three integers and three floats.' ) images[-1].append(Atom(atN, pos)) self.structures = images return
def setup(self): '''setup''' self.functional = self.inp.get('functional') or 'LDA' self.runtype = self.inp.get('runtype') or 'calc' self.eigensolver = self.inp.get('eigensolver') or 'cg' # this actually can't be none! _xyz = self.inp.get('xyz') if isinstance(_xyz, str): self.inputXYZ = _xyz self.atoms = read(self.inputXYZ) else: # support reading frm a dict (TODO: other type of objects - ?) from ase.atoms import Atoms from ase.atom import Atom self.atoms = \ Atoms([Atom(a[0],(a[1],a[2],a[3])) for a in _xyz]) # TODO: support multiple cell types self.atoms.cell = (self.inp['cell']['x'], self.inp['cell']['y'], self.inp['cell']['z']) # Mixer setup - only "broyden" supported self.mixer = self.inp.get('mixer') if self.mixer is None: self.mixer = Mixer else: self.mixer = BroydenMixer # Custom ID: allow to trace parameter set using a custom id self.custom_id = self.inp.get('custom_id') # Periodic Boundary Conditions self.atoms.pbc = False # This should not be done always self.atoms.center() self.nbands = self.inp.get('nbands') self.gpts = None self.setup_gpts() self.max_iterations = self.inp.get('maxiter') or 333 # Name: to be set by __str__ first time it is run self.name = None # self.logExtension = 'txt' self.dataExtension = 'gpw' # Timing / statistics self.lastElapsed = None
def colored(self, elements): res = Atoms() res.set_cell(self.get_cell()) for atom in self: elem = self.types[atom.tag] if elem in elements: elem = elements[elem] res.append(Atom(elem, atom.position)) return res
def get_structure(name): angle_w = math.radians(108) l_OH = 0.96 p1 = numpy.array([sin(angle_w / 2), cos(angle_w / 2), 0]) p2 = numpy.array([-sin(angle_w / 2), cos(angle_w / 2), 0]) curr_dir = os.path.dirname(os.path.abspath(__file__)) if "Zn" in name: f_name = os.path.join(curr_dir, "../data/Zn0.25V2O5(H2O)ICSD82328.cif") elif "Co" in name: f_name = os.path.join(curr_dir, "../data/Co0.25V2O5(H2O)ICSD50659.cif") else: return None mol = read(f_name) scaled_pos = mol.get_scaled_positions() ow = [(atom, i) for i, atom in enumerate(mol)\ if (scaled_pos[i][-1] < 0.52) \ and (scaled_pos[i][-1] > 0.48) \ and (atom.symbol == "O")] metals = [atom for atom in mol if atom.symbol in ("Co", "Zn")] # center of the octahedral # expand metals using unit cell cell = mol.cell m_pos = [] for m in metals: for i in (-1, 0, 1): for j in range(3): m_pos.append(m.position + i * cell[j, :]) # toward direction j with repeat i # search for closet # Look for the smallest distance and place H in the plane for o, i in ow: dist = [norm(o.position - mp) for mp in m_pos] mp = m_pos[numpy.argmin(dist)] # print("Zn", mp, "O", o.position) vec = (o.position - mp) / norm(o.position - mp) # unit vector from M->O r, theta, phi = cart_to_sph(vec) # print(vec, r, theta, phi) vec_xy = numpy.array([r * sin(theta) * cos(phi), r * sin(theta) * sin(phi), 0]) vec_n = numpy.cross(vec_xy, vec) vec_n = vec_n / numpy.linalg.norm(vec_n) # print(vec, p1) for p in (p1, p2): vec_ph = p[0] * vec_n + p[1] * vec # reconstruct in the vec, vec_n plane ph = o.position + vec_ph * l_OH h = Atom("H", ph) mol.append(h) # Add initial magmom symbols = numpy.array(mol.get_chemical_symbols()) # for comparison magmom = numpy.zeros(len(symbols)) magmom[symbols == "V"] = 0.25 magmom[symbols == "Co"] = 3.0 mol.set_initial_magnetic_moments(magmom) return mol
def add_atom(atoms, chem_potentials, beta, random_state, resolution=None): """ Perform a GCMC atomic addition Parameters ---------- atoms: ase.Atoms object The atomic configuration chem_potentials: dict A dictionary of {"Chemical Symbol": mu} where mu is a float denoting the chemical potential beta: float The thermodynamic beta random_state: np.random.RandomState object The random state to be used resolution: float or ndarray, optional If used denote the resolution for the voxels Returns ------- atoms or None: If the new configuration is accepted then the new atomic configuration is returned, else None """ # make the proposed system atoms_prime = dc(atoms) # make new atom new_symbol = np.random.choice(list(chem_potentials.keys())) e0 = atoms.get_potential_energy() if resolution is None: new_position = np.random.uniform(0, np.max(atoms.get_cell(), 0)) else: c = np.int32(np.ceil(np.diagonal(atoms.get_cell()) / resolution)) qvr = np.random.choice(np.product(c)) qv = np.asarray(np.unravel_index(qvr, c)) new_position = (qv + random_state.uniform(0, 1, 3)) * resolution new_atom = Atom(new_symbol, np.asarray(new_position)) # append new atom to system atoms_prime.append(new_atom) # get new energy delta_energy = atoms_prime.get_potential_energy() - e0 # get chemical potential mu = chem_potentials[new_symbol] # calculate acceptance if np.random.random() < np.exp( min([0, -1. * beta * delta_energy + beta * mu])): return atoms_prime else: return None
def main(): #config = ConfigParser.SafeConfigParser() config = ConfigParser.ConfigParser() config.read('config.ini') #print config main_paras = dict(config.items('main')) #print main_paras atoms = read(main_paras['structurefile'], index=main_paras['structure_slice'], format=main_paras['fileformat']) h_distances = np.array([0.6 + float(i) / 10.0 for i in range(10)]) bondlength = 1.6 traj = Trajectory('traj.traj', 'w') h_index = [] for index in range(len(atoms[0])): if atoms[0][index].symbol == 'H': h_index.append(index) h_index.sort(reverse=True) for p in atoms: for index in h_index: p.pop(i=index) center = np.mean(p.get_positions(), axis=0) print center for atom in p: distance = np.linalg.norm(center - atom.position) if distance > 2.0: dot = atom.position + bondlength * (atom.position - center) / distance perp_vector = perpendicular_vector(atom.position - center) unit_perp_vector = perp_vector / np.linalg.norm(perp_vector) for h_distance in h_distances: image = p.copy() image.append( Atom('H', dot + h_distance * unit_perp_vector / 2.0)) image.append( Atom('H', dot - h_distance * unit_perp_vector / 2.0)) #image=image.wrap(center=(0.5, 0.5, 0.5)) traj.write(image) break
def dict_atoms(d): atoms = Atoms([ Atom(atom['symbol'], position=atom['position'], tag=atom['tag'], momentum=atom['momentum'], magmom=atom['magmom'], charge=atom['charge']) for atom in d['atoms'] ], cell=d['cell'], pbc=d['pbc'], info=d['info'], constraint=[dict2constraint(c) for c in d['constraints']]) return atoms
def read_cmdft(fileobj): lines = fileobj.readlines() del lines[0] finished = False s = Atoms() while not finished: w = lines.pop(0).split() if w[0].startswith('"'): position = Bohr * np.array([float(w[3]), float(w[4]), float(w[5])]) s.append(Atom(w[0].replace('"', ''), position)) else: finished = True yield s
def main(): if not os.path.isdir('TMXR200X'): os.makedirs('TMXR200X') #for database in ['TM1R2006']: for database in database_files.keys(): fh = open(database_files[database]['module'].lower() + '.py', 'w') fh.write('# Computer generated code! Hands off!\n') fh.write('# Generated: ' + str(datetime.date.today()) + '\n') fh.write('from numpy import array\n') fh.write('data = ') data = {} # specification of molecules info = {} # reference/calculation info # download structures file = database_files[database]['pdf'] f = os.path.abspath(download_file(url_root, file, dir='TMXR200X')) f = pdftotext(f) geometries = read_geometries(f) # set number of unpaired electrons and charges no_unpaired_electrons = [] charges = [] for a in geometries: magmom = sum(a[1].get_initial_magnetic_moments()) if magmom > 0.0: no_unpaired_electrons.append((a[0], magmom)) charge = sum(a[1].get_charges()) if abs(charge) > 0.0: charges.append((a[0], charge)) data = format_data(database, geometries, no_unpaired_electrons, charges) # all constituent atoms atoms = [] for formula, geometry in geometries: atoms.extend(list(set(geometry.get_chemical_symbols()))) atoms = list(set(atoms)) atoms.sort() for atom in atoms: magmom = ground_state_magnetic_moments[atomic_numbers[atom]] data[atom] = { 'database': database, 'name': atom, 'symbols': atom, 'magmoms': [magmom], # None or list 'charges': None, # None or list 'positions': np.array([[0.0] * 3]), } Atom(atom, magmom=magmom) pprint.pprint(data, stream=fh) fh.close()
def read_gaussian(filename): """Reads a Gaussian input file""" f = open(filename, 'r') lines = f.readlines() f.close() atomsymbol = '\s*\D+\s*' atomnumber = '\s*\d+\s*' atomline = '.\s*((\D+)|(\d+))\s+[0-1]*\s*([-]*\d+\.\d+)\s+[-]*(\d+\.\d+)\s+[-]*(\d+\.\d+)' aline = re.compile(atomline) asym = re.compile(atomsymbol) anum = re.compile(atomnumber) atoms = Atoms() pbc = False cell = np.array([]) for line in lines: p = aline.search(line) if p is not None: a = p.group().split() if asym.search(a[0]) is not None: symbol = a[0] elif anum.search(a[0]) is not None: atomicnum = int(a[0]) symbol = chemical_symbols[atomicnum] if len(a) is 4: position = [float(a[1]), float(a[2]), float(a[3])] elif len(a) is 4: position = [float(a[2]), float(a[3]), float(a[4])] print(a) if symbol.find('Tv') == -1: atoms += Atom(symbol, position=position) isperiodic = False else: if not isperiodic: cell = np.zeros([3, 3]) cell[0][:] = position Ndim = 1 isperiodic = True else: cell[Ndim][:] = position Ndim += 1 if isperiodic: pbc = [True] * Ndim + [False] * (3 - Ndim) atoms.set_pbc(pbc) atoms.set_cell(cell) return atoms
def read_gaussian(filename): """Reads a Gaussian input file""" f = open(filename, 'r') lines = f.readlines() f.close() atoms = Atoms() for n, line in enumerate(lines): if ('#' in line): i = 0 while (lines[n + i + 5] != '\n'): info = lines[n + i + 5].split() symbol = info[0] position = [float(info[1]), float(info[2]), float(info[3])] atoms += Atom(symbol, position=position) i += 1 return atoms
def read_ref_coords(system_name, filename="coords"): skip = True list_atoms = [] with open(filename) as fp: for line in fp: if skip: skip = False continue temp = line.strip().split() list_atoms.append( Atom(temp[0], (float(temp[1]), float(temp[2]), float(temp[3])))) system = Atoms(list_atoms) return system.get_atomic_numbers(), system.get_positions()
def read_geometry(filename, dir='.'): fh = open(os.path.join(dir, filename), 'rb') lines = list(filter(read_geometry_filter, fh.readlines())) # return geometry in ASE format geometry = [] for line in lines: sline = line.split() # find chemical symbol (the symbols in the file are lowercase) symbol = sline[-1] for s in chemical_symbols: if symbol == s.lower(): symbol = s break geometry.append(Atom(symbol=symbol, position=sline[:-1])) fh.close() atoms = Atoms(geometry) atoms.set_positions(atoms.get_positions()*Bohr) # convert to Angstrom return atoms
def read_symbol(self, SYMBOL): # read NRLMOL SYMBOL input and convert it to ase.atoms object f = open(SYMBOL, 'r') ll = f.readlines() f.close() atoms = Atoms() for l in range(len(ll)): if ll[l].find('ALL') != -1 or ll[l].find('BHS') != -1: tmp = ll[l].split() # atom = px py pz s atom = tmp[0].split('-')[-1][0:3] px = float(tmp[2]) * Bohr py = float(tmp[3]) * Bohr pz = float(tmp[4]) * Bohr s = tmp[5] a = Atom(self.nrlmol2elements(atom), [px, py, pz]) atoms.append(a) self.atoms = atoms
def __getitem__(self, i): """Return a subset of the atoms. i -- scalar integer, list of integers, or slice object describing which atoms to return. If i is a scalar, return an Atom object. If i is a list or a slice, return an Atoms object with the same cell, pbc, and other associated info as the original Atoms object. The indices of the constraints will be shuffled so that they match the indexing in the subset returned. """ if isinstance(i, int): natoms = len(self) if i < -natoms or i >= natoms: raise IndexError('Index out of range.') return Atom(atoms=self, index=i) import copy from ase.constraints import FixConstraint atoms = self.__class__(cell=self._cell, pbc=self._pbc) # TODO: Do we need to shuffle indices in adsorbate_info too? atoms.adsorbate_info = self.adsorbate_info atoms.arrays = {} for name, a in self.arrays.items(): atoms.arrays[name] = a[i].copy() # Constraints need to be deepcopied, since we need to shuffle # the indices atoms.constraints = copy.deepcopy(self.constraints) condel = [] for con in atoms.constraints: if isinstance(con, FixConstraint): try: con.index_shuffle(i) except IndexError: condel.append(con) for con in condel: atoms.constraints.remove(con) return atoms
def main(): atoms = read('POSCAR') # atoms.center() layers = find_layers(atoms.copy()) inner_site = {} n_site = 0 for key in layers.keys(): new_sites, n_site = find_positions(layers[key][-1], n_site) if key == 0: outer_site = new_sites continue inner_site.update(new_sites) n_Pd = 147 n_H = int(n_Pd * 0.4) n_inners = int(n_H * 0.5) #print inner_site.keys() #inners = random.sample(random.shuffle(inner_site.keys()), n_inners) #outers = random.sample(random.shuffle(outer_site.keys()), n_H - n_inners) inner_keys = inner_site.keys() outer_keys = outer_site.keys() #np.random.shuffle(inner_keys) #np.random.shuffle(outer_keys) #print inner_keys inners = random.sample(inner_keys, n_inners) outers = random.sample(outer_keys, n_H - n_inners) print outers print inners #print n_inners for key in inners: if inner_site[key][0] == 'bridge': atoms.append( Atom('H', inner_site[key][1] + inner_site[key][2] * 0.4)) if inner_site[key][0] == 'hollow': if inner_site[key][3] > 0: atoms.append( Atom('H', inner_site[key][1] + inner_site[key][2] * 0.6)) else: atoms.append( Atom('H', inner_site[key][1] - inner_site[key][2] * 0.6)) for key in outers: if outer_site[key][0] == 'bridge': atoms.append( Atom('H', outer_site[key][1] + outer_site[key][2] * 0.4)) if outer_site[key][0] == 'hollow': if outer_site[key][3] > 0: atoms.append( Atom('H', outer_site[key][1] + outer_site[key][2] * 0.5)) else: atoms.append( Atom('H', outer_site[key][1] - outer_site[key][2] * 0.5)) write('CONTCAR', atoms, format='vasp')
def parse_relax(label, write_traj=False, pbc=False, cell=None, chemical_symbols=[]): f = open(label + '.relax') #f = open(label + '.restart') text = f.read() # Parse out the steps if text == '': return None steps = text.split(':RELAXSTEP:')[1:] if write_traj == False: steps = [steps[-1]] else: traj = Trajectory(label + '.traj', mode='w') # Parse out the energies n_geometric = len(steps) s = os.popen('grep "Total free energy" ' + label + '.out') engs = s.readlines()[-n_geometric:] engs = [float(a.split()[-2]) * Hartree for a in engs] s.close() # build a traj file out of the steps for j, step in enumerate(steps): positions = step.split(':')[2].strip().split('\n') forces = step.split(':')[4].strip().split('\n') frc = np.empty((len(forces), 3)) atoms = Atoms() for i, f in enumerate(forces): frc[i, :] = [float(a) * Hartree / Bohr for a in f.split()] atoms += Atom(chemical_symbols[i], [float(a) * Bohr for a in positions[i].split()]) atoms.set_calculator( SinglePointCalculator(atoms, energy=engs[j], forces=frc)) atoms.set_pbc(pbc) atoms.cell = cell if write_traj == True: traj.write(atoms) atoms.set_calculator() return atoms
def read_I_info(fileobj, index=-1): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() del lines[0] finished = False s = Atoms() while not finished: w = lines.pop(0).split() if w[0].startswith('"'): position = Bohr * np.array([float(w[3]), float(w[4]), float(w[5])]) s.append(Atom(w[0].replace('"',''), position)) else: finished = True return s
def read_dacapo_text(fileobj): if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() i = lines.index(' Structure: A1 A2 A3\n') cell = np.array([[float(w) for w in line.split()[2:5]] for line in lines[i + 1:i + 4]]).transpose() i = lines.index(' Structure: >> Ionic positions/velocities ' + 'in cartesian coordinates <<\n') atoms = [] for line in lines[i + 4:]: words = line.split() if len(words) != 9: break Z, x, y, z = words[2:6] atoms.append(Atom(int(Z), [float(x), float(y), float(z)])) atoms = Atoms(atoms, cell=cell.tolist()) try: i = lines.index( ' DFT: CPU time Total energy\n') except ValueError: pass else: column = lines[i + 3].split().index('selfcons') - 1 try: i2 = lines.index(' ANALYSIS PART OF CODE\n', i) except ValueError: pass else: while i2 > i: if lines[i2].startswith(' DFT:'): break i2 -= 1 energy = float(lines[i2].split()[column]) atoms.set_calculator( SinglePointCalculator(energy, None, None, None, atoms)) return atoms
atoms.center() view(atoms) """ # Si nano-dot with open('Si29H36.ion', 'r') as f: txt = f.read() Si = txt.split('Si')[1] Si, H = Si.split('H') atoms = Atoms() for element, coord_set in zip(['Si', 'H'], [Si, H]): for line in coord_set.splitlines()[1:-1]: atoms += Atom(symbol=element, position=[float(a) * Bohr for a in line.split()]) atoms.set_cell([21] * 3) atoms.center() add_to_dict(AseAtomsAdaptor.get_structure(atoms), 'Si_nanodot') # PV=nRT @ 100 bar, 100 C atoms = make_box_of_molecules(Atoms('He'), 75, [33.811] * 3) add_to_dict(AseAtomsAdaptor.get_structure(atoms), 'He_box') # water # liquid water at room temp, 55.555 mol/L water = molecule('H2O') water.set_distance(0, 1, 1.0, fix=0) water.set_distance(0, 2, 1.0, fix=0)
def __init__(self, position, charge): Atom.__init__(self, position=position, charge=charge)
add_to_dict(AseAtomsAdaptor.get_structure(atoms), 'polyacetylene') # MoS2 with open('MoS2') as f: txt = f.read() header, Mo, S = txt.split(':') MoS2 = Atoms() for element, block in zip(['Mo', 'S'], [Mo, S]): b = block.splitlines() for line in b[1:-1]: MoS2 += Atom(position=[float(a) * Bohr for a in line.split()], symbol=element) MoS2.set_cell([27, 27, 6.017129910500000 * Bohr]) MoS2.center() MoS2.rotate(90, 'y', rotate_cell=True) #MoS2.set_cell([MoS2.cell[0] * -1, MoS2.cell[1], MoS2.cell[2]]) MoS2.set_cell([MoS2.cell[2], MoS2.cell[1], MoS2.cell[0] * -1]) MoS2.center() #view(MoS2) add_to_dict(AseAtomsAdaptor.get_structure(MoS2), 'MoS2_nanotube') lens = [] for n, s in structures.items(): lens.append(len(Structure.from_dict(s))) #print(len(Structure.from_dict(s)))
def make_srs_c8(names,sizes): #work out the expansion factor #dist0 = furthest_dummy(mol0) #dist1 = furthest_dummy(mol1) factor = sum(sizes) #dist0 + dist1 factor = factor * 2 a = 1.4142 * factor #This is an interesting net, as specified, the chirality can go either way: there are 6 N adjacent to each carbon # each N, in turn can equally bond two different pairs of C # C -> triangles, N => midpoints #srs_c8 = crystal(['C', 'N'], [(0.25, 0.25, 0.25), (0.25, 0.0, 0.5)], spacegroup=211, #I432 # cellpar=[a, a, a, 90, 90, 90]) # The confusion is removed by specifying extra 'F' atoms srs_c8 = crystal(['C', 'N', 'F'], [(0.25, 0.25, 0.25), (0.25, 0.0, 0.5), (0.25, 0.625, 0.125)], spacegroup=211, #I432 cellpar=[a, a, a, 90, 90, 90]) write('test.cif',srs_c8) eps = 0.05 model_molecule={} n_obj = -1 #initialise to -1 such that it can be indexed at start of add n_tags = 0 #First detect global bonding cov_rad=[] for atom in srs_c8: #cov_rad.append(covalent_radii[atom.number]) cov_rad.append(factor / 4) print cov_rad nlist = NeighborList(cov_rad,skin=0.1,self_interaction=False,bothways=True) nlist.build(srs_c8) #To sort out tags, we need to label each bond nbond = 1 bond_matrix = np.zeros( (len(srs_c8),len(srs_c8)) ) pbc_bond_matrix = np.zeros( (len(srs_c8),len(srs_c8)) ) bond_dict = {} for atom in srs_c8: print "---------------------" indices, offsets = nlist.get_neighbors(atom.index) for index,offset in zip(indices,offsets): print atom.index, index, atom.symbol, srs_c8[index].symbol, offset, srs_c8.get_distance(atom.index,index,mic=True) if atom.index < index: this_bond = [atom.index, index] for o in offset: this_bond.append(o) bond = tuple(this_bond) print bond bond_dict[bond] = nbond #Now we need to find the same bond the other direction to get the offsets right indices2,offsets2 = nlist.get_neighbors(index) for i2,o2 in zip(indices2,offsets2): if i2 == atom.index: #print "sum of offsets = ", offset, o2, sum(offset + o2) if sum(offset + o2) == 0: #same bond this_bond = [index, atom.index] for o in o2: this_bond.append(o) bond = tuple(this_bond) print bond bond_dict[bond] = nbond nbond +=1 print "Bond dict:" print nbond for k,v in sorted(bond_dict.items()): print k,v print "End Bond dict:" #Want to delete bonds that don't have a F at the midpoint for k,v in sorted(bond_dict.items()): print "--------------------------" print k i1,i2,o1,o2,o3 = k if (srs_c8[i1].symbol == 'C' and srs_c8[i2].symbol == 'N') or (srs_c8[i1].symbol == 'N' and srs_c8[i2].symbol == 'C'): offset = [abs(o1),abs(o2),abs(o3)] position1 = srs_c8.positions[i1] position2 = srs_c8.positions[i2] position2_mic = srs_c8.positions[i2] + np.dot(offset, srs_c8.get_cell()) midpoint = Atom() if any(o != 0 for o in offset): midpoint.position = srs_c8[i1].position + (position2_mic - srs_c8[i1].position)/2 print position1, midpoint.position, position2 else: midpoint.position = srs_c8[i1].position + (srs_c8[i2].position - srs_c8[i1].position)/2 match = False for a2 in srs_c8: if a2.symbol == 'F': if np.allclose(a2.position, midpoint.position): print "Found a F" match = True continue if not match: print "deleting", k del bond_dict[k] else: print "not CN/NC, deleting", k del bond_dict[k] print "New Bond dict:" print len(bond_dict) for k,v in sorted(bond_dict.items()): i1,i2,o1,o2,o3 = k position1 = srs_c8.positions[i1] position2 = srs_c8.positions[i2] position2_mic = srs_c8.positions[i2] + np.dot([o1,o2,o3], srs_c8.get_cell()) this_dist = np.linalg.norm(position1 - position2) this_dist_mic = np.linalg.norm(position1 - position2_mic) print k,v, this_dist,this_dist_mic print "End New Bond dict:" #Start with C (triangles) for atom in srs_c8: if atom.symbol == 'C': print'=======================================' print 'C Atom ',atom.index n_obj+=1 model_molecule[n_obj] = Atoms() model_molecule[n_obj] += atom model_molecule[n_obj][0].original_index = atom.index model_molecule[n_obj][0].symbol = 'F' indices, offsets = nlist.get_neighbors(atom.index) #Just checking the symbols here print indices print offsets symbols = ([srs_c8[index].symbol for index in indices]) symbol_string = ''.join(sorted([srs_c8[index].symbol for index in indices])) #print symbol_string #for i,o in zip(indices, offsets): # print i,o for index,offset in zip(indices,offsets): print atom.index, index, offset this_bond = [atom.index, index] for o in offset: this_bond.append(o) bond = tuple(this_bond) #print bond_dict[bond] if srs_c8[index].symbol == 'N' and bond in bond_dict: if any(o != 0 for o in offset): #If we're going over a periodic boundary, we need to negate the tag model_molecule[n_obj] += srs_c8[index] model_molecule[n_obj].positions[-1] = srs_c8.positions[index] + np.dot(offset, srs_c8.get_cell()) model_molecule[n_obj][-1].tag = -bond_dict[bond] else: model_molecule[n_obj] += srs_c8[index] model_molecule[n_obj][-1].tag = bond_dict[bond] model_molecule[n_obj].positions[-1] = srs_c8.positions[index] + np.dot(offset, srs_c8.get_cell()) n_centers = n_obj # # ##Now we do the N (edges) for atom in srs_c8: if atom.symbol == 'N': #print'=======================================' #print 'N Atom ',atom.index, " finding edges" n_obj+=1 model_molecule[n_obj] = Atoms() model_molecule[n_obj] += atom indices, offsets = nlist.get_neighbors(atom.index) for index,offset in zip(indices,offsets): print index, offset, srs_c8[index].symbol this_bond = [atom.index, index] for o in offset: this_bond.append(o) bond = tuple(this_bond) #if not bond_dict.has_key(bond): #Then if srs_c8[index].symbol == 'C' and bond in bond_dict: if any(o != 0 for o in offset): #If we're going over a periodic boundary, we need to negate the tag model_molecule[n_obj] += srs_c8[index] model_molecule[n_obj].positions[-1] = srs_c8.positions[index] + np.dot(offset, srs_c8.get_cell()) model_molecule[n_obj][-1].tag = -bond_dict[bond] else: model_molecule[n_obj] += srs_c8[index] model_molecule[n_obj][-1].tag = bond_dict[bond] model_molecule[n_obj].positions[-1] = srs_c8.positions[index] + np.dot(offset, srs_c8.get_cell()) # # # f = open('srs_c8.model','w') g = open('control-mofgen.txt','w') #Just for checking, now lets gather everything in the model_molecule dict into one big thing and print it #test_mol = Atoms() #for obj in model_molecule: # test_mol += model_molecule[obj] #write('test_model.xyz',test_mol) #print n_centers, n_model, n_obj #Headers and cell f.write('%-20s %-3d\n' %('Number of objects =',n_obj+1)) f.write('%-20s\n' %('build = systre')) f.write('%5s\n' %('Cell:')) f.write('%8.3f %8.3f %8.3f \n' % (srs_c8.get_cell()[0][0], srs_c8.get_cell()[0][1], srs_c8.get_cell()[0][2])) f.write('%8.3f %8.3f %8.3f \n' % (srs_c8.get_cell()[1][0], srs_c8.get_cell()[1][1], srs_c8.get_cell()[1][2])) f.write('%8.3f %8.3f %8.3f \n' % (srs_c8.get_cell()[2][0], srs_c8.get_cell()[2][1], srs_c8.get_cell()[2][2])) g.write('%-20s\n' %('model = srs_c8')) #Now write stuff for obj in xrange(n_centers+1): f.write('\n%-8s %-3d\n' %('Center: ', obj+1)) f.write('%-3d\n' %(len(model_molecule[obj]))) f.write('%-20s\n' %('type = triangle')) #process positions to make it a bit more ideal for atom in model_molecule[obj]: #if atom.symbol == 'C': if atom.index != 0: model_molecule[obj].set_distance(atom.index,0,1.0,fix=1) for atom in model_molecule[obj]: (x,y,z) = atom.position #print atom.symbol, atom.position, atom.tag if atom.tag: f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % ('X', x, y, z, atom.tag)) #f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % (atom.symbol, x, y, z, atom.tag)) else: f.write('%-2s %15.8f %15.8f %15.8f\n' % ('Q', x, y, z)) #f.write('%-2s %15.8f %15.8f %15.8f\n' % (atom.symbol, x, y, z)) g.write('%-9s %-50s\n' %('center =', names[0])) for obj in xrange(n_centers+1,n_obj+1): f.write('\n%-8s %-3d\n' %('Linker: ', obj-n_centers)) f.write('%-3d\n' %(len(model_molecule[obj]))) f.write('%-20s\n' %('type = linear')) #process positions to make it a bit more ideal for atom in model_molecule[obj]: #if atom.symbol == 'C': if atom.index != 0: model_molecule[obj].set_distance(atom.index,0,1.0,fix=1) for atom in model_molecule[obj]: (x,y,z) = atom.position #print atom.symbol, atom.position, atom.tag if atom.tag: f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % ('X', x, y, z, atom.tag)) #f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % (atom.symbol, x, y, z, atom.tag)) else: f.write('%-2s %15.8f %15.8f %15.8f\n' % ('Q', x, y, z)) #f.write('%-2s %15.8f %15.8f %15.8f\n' % (atom.symbol, x, y, z)) g.write('%-9s %-50s\n' %('linker =', names[1])) # # test_mol = Atoms() for obj in model_molecule: test_mol += model_molecule[obj] # write('test_model2.xyz',test_mol)
sym_dict = { 'carbon': 'C', 'oxygen': 'O', 'hydrogen': 'H', 'lithium': 'Li', 'fluorine': 'F', 'phosphorus': 'P' } positions = positions.splitlines()[1:] atoms = Atoms() for line in positions: element, x, y, z = line.split() position = [float(a) * Bohr for a in [x, y, z]] atoms += Atom(symbol=sym_dict[element], position=position) atoms.set_cell(lattice) atoms.set_pbc([True] * 3) add_to_dict(atoms, 'electrolyte', 273.15 + 23) # iron interface #atoms = read('interface.traj') #add_to_dict(atoms, 'iron_interface', 273.15 + 23) json.dump(structures, open('../../test_set/MD.json', 'w')) json.dump(params_dict, open('../../test_set/MD_parameters.json', 'w'))
def read_geometries(filename, dir='.'): txt = os.path.join(dir, filename) fh = open(txt, 'rb') table = fh.read() firstsplit = '(in xyz format):' # TM1R2006 and TM2R2007 dataformat = 'xyz' if table.find('(Gaussian archive entries):') != -1: firstsplit = '(Gaussian archive entries):' # TM3R2008 dataformat = 'gaussian' table = table.split(firstsplit) table = table[1] # remove one or two digit numbers (page numbers/numbers of atoms in xyz format) table = re.sub('\n\d\d\n', '\n', table) table = re.sub('\n\d\n', '\n', table) # remove S + two digit numbers (page numbers) table = re.sub('\nS\d\d\n', '\n', table) # remove S + one digit (page numbers) table = re.sub('\nS\d\n', '\n', table) # remove empty lines # http://stackoverflow.com/questions/1140958/whats-a-quick-one-liner-to-remove-empty-lines-from-a-python-string table = os.linesep.join([s for s in table.splitlines() if s]) geometries = [] if dataformat == 'xyz': # split on new lines table = table.split('\n') # mark compound names with ':' tags for n, line in enumerate(table): if not (line.find('.') != -1): # remove method/basis set information table[n] = table[n].replace(' BP86/qzvp', '') table[n] = ':' + table[n] + ':' table = '\n'.join([s for s in table]) # split into compounds # http://simonwillison.net/2003/Oct/26/reSplit/ # http://stackoverflow.com/questions/647655/python-regex-split-and-special-character table = re.compile('(:.*:)').split(table) # remove empty elements table = [l.strip() for l in table] table = [l for l in table if len(l) > 1] # extract compounds for n in range(0, len(table), 2): compound = table[n].replace(':', '').replace(' ', '_') geometry = [] for atom in table[n + 1].split('\n'): geometry.append( Atom(symbol=atom.split()[0], position=atom.split()[1:])) atoms = Atoms(geometry) # set the charge and magnetic moment on the heaviest atom (better ideas?) heaviest = max([a.get_atomic_number() for a in atoms]) heaviest_index = [a.get_atomic_number() for a in atoms].index(heaviest) charge = 0.0 if abs(charge) > 0.0: charges = [0.0 for a in atoms] charges[heaviest_index] = charge atoms.set_charges(charges) if compound in [ # see corresponding articles 'Ti(BH4)3', # TM1R2006 'V(NMe2)4', # TM1R2006 'Cu(acac)2', # TM1R2006 'Nb(Cp)(C7H7)_Cs', # TM2R2007 'CdMe_C3v', # TM2R2007 ]: multiplicity = 2.0 else: multiplicity = 1.0 if multiplicity > 1.0: magmoms = [0.0 for a in atoms] magmoms[heaviest_index] = multiplicity - 1 atoms.set_initial_magnetic_moments(magmoms) geometries.append((compound, atoms)) elif dataformat == 'gaussian': # remove new lines table = table.replace('\n', '') # fix: MeHg(Cl) written as MeHg(CN) table = table.replace( 'MeHg(CN), qzvp (SDD/def-qzvp for metal)\\\\0,1\\Hg,0.,0.,0.1975732257', 'MeHg(Cl), qzvp (SDD/def-qzvp for metal)\\\\0,1\\Hg,0.,0.,0.1975732257' ) # split on compound end marks table = table.split('\\\@') # remove empty elements table = [l.strip() for l in table] table = [l for l in table if len(l) > 1] # extract compounds for n, line in enumerate(table): # split on gaussian separator '\\' entries = line.split('\\\\') compound = entries[2].split(',')[0].split(' ')[0] # charge and multiplicity from gaussian archive charge, multiplicity = entries[3].split('\\')[0].split(',') charge = float(charge) multiplicity = float(multiplicity) if compound in ['Au(Me)PMe3']: # in gzmat format! # check openbabel version (babel >= 2.2 needed) cmd = popen3('babel -V')[1] output = cmd.read().strip() cmd.close() v1, v2, v3 = output.split()[2].split('.') v1, v2, v3 = int(v1), int(v2), int(v3) if not (v1 > 2 or ((v1 == 2) and (v2 >= 2))): print compound + ': skipped - version of babel does not support gzmat format' continue # this one is given in z-matrix format finame = compound.replace('(', '').replace(')', '') + '.orig' foname = finame.split('.')[0] + '.xyz' fi = open(finame, 'w') fo = open(foname, 'w') if 1: # how to extract zmat by hand zmat = ['#'] # must start with gaussian input start zmat.extend('@') # separated by newline zmat.extend([compound]) zmat.extend('@') # separated by newline zmat.extend( [str(int(charge)) + ' ' + str(int(multiplicity))]) zmat.extend(entries[3].replace(',', ' ').split('\\')[1:]) zmat.extend( '@' ) # atom and variable definitions separated by newline zmat.extend(entries[4].split('\\')) zmat.extend('@') # end with newline for l in zmat: fi.write(l.replace('@', '').replace('=', ' ') + '\n') fi.close() if 0: # or use the whole gausian archive entry entries = ''.join(entries) fi.write(entries) # convert gzmat into xyz using openbabel (babel >= 2.2 needed) cmd = popen3('babel -i gzmat ' + finame + ' -o xyz ' + foname)[2] error = cmd.read().strip() cmd.close() fo.close() if not (error.find('0 molecules') != -1): atoms = ase.io.read(foname) else: print compound + ': babel conversion failed' continue # conversion failed else: positions = entries[3].replace(',', ' ').split('\\')[1:] geometry = [] for k, atom in enumerate(positions): geometry.append( Atom(symbol=atom.split()[0], position=[float(p) for p in atom.split()[1:]])) atoms = Atoms(geometry) # # set the charge and magnetic moment on the heaviest atom (better ideas?) heaviest = max([a.get_atomic_number() for a in atoms]) heaviest_index = [a.get_atomic_number() for a in atoms].index(heaviest) if abs(charge) > 0.0: charges = [0.0 for a in atoms] charges[heaviest_index] = charge atoms.set_charges(charges) if multiplicity > 1.0: magmoms = [0.0 for a in atoms] magmoms[heaviest_index] = multiplicity - 1 atoms.set_initial_magnetic_moments(magmoms) geometries.append((compound, atoms)) return geometries
def __init__(self, symbol="X", position=(0, 0, 0), tag=None, momentum=None, mass=None, magmom=None, charge=None, atoms=None, index=None, pse=None, element=None, **qwargs): if element is None: element = symbol SparseArrayElement.__init__(self, **qwargs) # super(SparseArrayElement, self).__init__(**qwargs) # verify that element is given (as string, ChemicalElement object or nucleus number if pse is None: pse = PeriodicTable() if element is None or element == "X": if "Z" in qwargs: el_symbol = pse.atomic_number_to_abbreviation(qwargs["Z"]) self._lists["element"] = pse.element(el_symbol) else: if isinstance(element, string_types): el_symbol = element self._lists["element"] = pse.element(el_symbol) elif isinstance(element, str): el_symbol = element self._lists["element"] = pse.element(el_symbol) elif isinstance(element, ChemicalElement): self._lists["element"] = element else: raise ValueError("Unknown element type") # KeyError handling required for user defined elements try: ASEAtom.__init__(self, symbol=symbol, position=position, tag=tag, momentum=momentum, mass=mass, magmom=magmom, charge=charge, atoms=atoms, index=index) except KeyError: symbol = pse.Parent[symbol] ASEAtom.__init__(self, symbol=symbol, position=position, tag=tag, momentum=momentum, mass=mass, magmom=magmom, charge=charge, atoms=atoms, index=index) # ASE compatibility for tags for key, val in qwargs.items(): self.data[key] = val
def make_Td(names, sizes): #work out the expansion factor factor = sum(sizes) #factor = 3.0 Td = Atoms() Td.append(Atom('F', position=(0, 0, 0))) Td.append(Atom('N', position=(0, 0, factor))) #Atom 3 Td.append(Atom('N', position=(1.0, 0, 0.0))) Td.set_angle([1, 0, 2], 1.91062939) Td.set_distance(0, 2, factor, fix=0) #Atom 4 Td.append(Atom('N', position=(1.0, 0, 0.0))) Td.set_distance(0, 3, factor, fix=0) Td.set_angle([1, 0, 3], 1.91062939, mask=None) Td.set_dihedral([2, 1, 0, 3], 2.0943951, mask=None) #print Td.get_angle([1,0,2]) #Atom 5 Td.append(Atom('N', position=(1.0, 0, 0))) Td.set_angle([1, 0, 4], 1.91062939) Td.set_dihedral([2, 1, 0, 4], -2.0943951) Td.set_distance(0, 4, factor, fix=0) #find side centroids tmp1 = Td[1:4] coside = tmp1.get_center_of_mass() Td.append(Atom('C', position=coside)) # tmp1 = Td[2:5] coside = tmp1.get_center_of_mass() Td.append(Atom('C', position=coside)) # tmp1 = Td[3:5] tmp1.append(Td[1]) coside = tmp1.get_center_of_mass() Td.append(Atom('C', position=coside)) # tmp1 = Td[1:3] tmp1.append(Td[4]) coside = tmp1.get_center_of_mass() Td.append(Atom('C', position=coside)) write('td.xyz', Td) # Now we make tags etc ## C -> triangles (faces), N => triangle caps eps = 0.05 model_molecule = {} n_obj = -1 #initialise to -1 such that it can be indexed at start of add n_tags = 0 #First detect global bonding cov_rad = [] for atom in Td: #cov_rad.append(covalent_radii[atom.number]) cov_rad.append(factor / 2) nlist = NeighborList(cov_rad, skin=0.1, self_interaction=False, bothways=True) nlist.build(Td) nbond = 1 bond_matrix = np.zeros((len(Td), len(Td))) pbc_bond_matrix = np.zeros((len(Td), len(Td))) bond_dict = {} for atom in Td: print "---------------------" indices, offsets = nlist.get_neighbors(atom.index) for index, offset in zip(indices, offsets): print atom.index, index, atom.symbol, Td[ index].symbol, offset, Td.get_distance(atom.index, index, mic=True) if atom.index < index: this_bond = [atom.index, index] for o in offset: this_bond.append(o) bond = tuple(this_bond) print bond bond_dict[bond] = nbond #Now we need to find the same bond the other direction to get the offsets right indices2, offsets2 = nlist.get_neighbors(index) for i2, o2 in zip(indices2, offsets2): if i2 == atom.index: #print "sum of offsets = ", offset, o2, sum(offset + o2) if sum(offset + o2) == 0: #same bond this_bond = [index, atom.index] for o in o2: this_bond.append(o) bond = tuple(this_bond) print bond bond_dict[bond] = nbond nbond += 1 print nbond for k, v in bond_dict.items(): print k, v #Now we look for all the things with unit*factor bondlengths #Start with N (rectangles) for atom in Td: if atom.symbol == 'N': print '=======================================' print 'N Atom ', atom.index n_obj += 1 model_molecule[n_obj] = Atoms() model_molecule[n_obj] += atom model_molecule[n_obj][0].original_index = atom.index model_molecule[n_obj][0].symbol = 'F' indices, offsets = nlist.get_neighbors(atom.index) #Just checking the symbols here print indices print offsets symbols = ([Td[index].symbol for index in indices]) symbol_string = ''.join( sorted([Td[index].symbol for index in indices])) #print symbol_string #for i,o in zip(indices, offsets): # print i,o for index, offset in zip(indices, offsets): print atom.index, index, offset this_bond = [atom.index, index] for o in offset: this_bond.append(o) bond = tuple(this_bond) print bond_dict[bond] if Td[index].symbol == 'C': #By definition, we can't be going over a periodic boundary (no pbc) model_molecule[n_obj] += Td[index] model_molecule[n_obj][-1].tag = bond_dict[bond] model_molecule[n_obj].positions[-1] = Td.positions[index] n_centers = n_obj ##Now we do the C (triangles) for atom in Td: if atom.symbol == 'C': #print'=======================================' #print 'N Atom ',atom.index, " finding squares1" n_obj += 1 model_molecule[n_obj] = Atoms() model_molecule[n_obj] += atom indices, offsets = nlist.get_neighbors(atom.index) for index, offset in zip(indices, offsets): print index, offset, Td[index].symbol this_bond = [atom.index, index] for o in offset: this_bond.append(o) bond = tuple(this_bond) #if not bond_dict.has_key(bond): #Then if Td[index].symbol == 'N': #By definition, we can't be going over a periodic boundary (no pbc) model_molecule[n_obj] += Td[index] model_molecule[n_obj][-1].tag = bond_dict[bond] model_molecule[n_obj].positions[-1] = Td.positions[index] f = open('Td.model', 'w') g = open('control-mofgen.txt', 'w') #Just for checking, now lets gather everything in the model_molecule dict into one big thing and print it test_mol = Atoms() for obj in model_molecule: test_mol += model_molecule[obj] write('test_model.xyz', test_mol) #print n_centers, n_model, n_obj #Headers and cell f.write('%-20s %-3d\n' % ('Number of objects =', n_obj + 1)) f.write('%-20s\n' % ('build = systre')) f.write('%5s\n' % ('Cell:')) f.write('%8.3f %8.3f %8.3f \n' % (0.0, 0.0, 0.0)) f.write('%8.3f %8.3f %8.3f \n' % (0.0, 0.0, 0.0)) f.write('%8.3f %8.3f %8.3f \n' % (0.0, 0.0, 0.0)) g.write('%-20s\n' % ('model = Td')) for obj in xrange(n_centers + 1): f.write('\n%-8s %-3d\n' % ('Center: ', obj + 1)) f.write('%-3d\n' % (len(model_molecule[obj]))) f.write('%-20s\n' % ('type = triangle')) #process positions to make it a bit more ideal for atom in model_molecule[obj]: #if atom.symbol == 'C': if atom.index != 0: model_molecule[obj].set_distance(atom.index, 0, 1.0, fix=1) for atom in model_molecule[obj]: (x, y, z) = atom.position #print atom.symbol, atom.position, atom.tag if atom.tag: f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % ('X', x, y, z, atom.tag)) #f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % (atom.symbol, x, y, z, atom.tag)) else: f.write('%-2s %15.8f %15.8f %15.8f\n' % ('Q', x, y, z)) #f.write('%-2s %15.8f %15.8f %15.8f\n' % (atom.symbol, x, y, z)) g.write('%-9s %-50s\n' % ('center =', names[0])) for obj in xrange(n_centers + 1, n_obj + 1): f.write('\n%-8s %-3d\n' % ('Linker: ', obj - n_centers)) f.write('%-3d\n' % (len(model_molecule[obj]))) f.write('%-20s\n' % ('type = triangle')) #process positions to make it a bit more ideal for atom in model_molecule[obj]: #if atom.symbol == 'C': if atom.index != 0: model_molecule[obj].set_distance(atom.index, 0, 1.0, fix=1) for atom in model_molecule[obj]: (x, y, z) = atom.position #print atom.symbol, atom.position, atom.tag if atom.tag: f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % ('X', x, y, z, atom.tag)) #f.write('%-2s %15.8f %15.8f %15.8f %-4s\n' % (atom.symbol, x, y, z, atom.tag)) else: f.write('%-2s %15.8f %15.8f %15.8f\n' % ('Q', x, y, z)) #f.write('%-2s %15.8f %15.8f %15.8f\n' % (atom.symbol, x, y, z)) g.write('%-9s %-50s\n' % ('linker =', names[1])) test_mol = Atoms() for obj in model_molecule: test_mol += model_molecule[obj] write('test_model2.xyz', test_mol)
def add_adsorbate(slab, adsorbate, height, position=(0, 0), offset=None, mol_index=0): """Add an adsorbate to a surface. This function adds an adsorbate to a slab. If the slab is produced by one of the utility functions in ase.build, it is possible to specify the position of the adsorbate by a keyword (the supported keywords depend on which function was used to create the slab). If the adsorbate is a molecule, the atom indexed by the mol_index optional argument is positioned on top of the adsorption position on the surface, and it is the responsibility of the user to orient the adsorbate in a sensible way. This function can be called multiple times to add more than one adsorbate. Parameters: slab: The surface onto which the adsorbate should be added. adsorbate: The adsorbate. Must be one of the following three types: A string containing the chemical symbol for a single atom. An atom object. An atoms object (for a molecular adsorbate). height: Height above the surface. position: The x-y position of the adsorbate, either as a tuple of two numbers or as a keyword (if the surface is produced by one of the functions in ase.build). offset (default: None): Offsets the adsorbate by a number of unit cells. Mostly useful when adding more than one adsorbate. mol_index (default: 0): If the adsorbate is a molecule, index of the atom to be positioned above the location specified by the position argument. Note *position* is given in absolute xy coordinates (or as a keyword), whereas offset is specified in unit cells. This can be used to give the positions in units of the unit cell by using *offset* instead. """ info = slab.adsorbate_info if 'cell' not in info: info['cell'] = slab.get_cell()[:2, :2] pos = np.array([0.0, 0.0]) # (x, y) part spos = np.array([0.0, 0.0]) # part relative to unit cell if offset is not None: spos += np.asarray(offset, float) if isinstance(position, str): # A site-name: if 'sites' not in info: raise TypeError('If the atoms are not made by an ' + 'ase.build function, ' + 'position cannot be a name.') if position not in info['sites']: raise TypeError('Adsorption site %s not supported.' % position) spos += info['sites'][position] else: pos += position pos += np.dot(spos, info['cell']) # Convert the adsorbate to an Atoms object if isinstance(adsorbate, Atoms): ads = adsorbate elif isinstance(adsorbate, Atom): ads = Atoms([adsorbate]) else: # Assume it is a string representing a single Atom ads = Atoms([Atom(adsorbate)]) # Get the z-coordinate: try: a = info['top layer atom index'] except KeyError: a = slab.positions[:, 2].argmax() info['top layer atom index'] = a z = slab.positions[a, 2] + height # Move adsorbate into position ads.translate([pos[0], pos[1], z] - ads.positions[mol_index]) # Attach the adsorbate slab.extend(ads)