def append_and_write_COMs(result_dict, structure, file, suffix='.cif'): """ Append all COMs in result dict to the ASE structure. Window COMs: He cage COM: Ne optimized pore COM: Ar """ for molecule in result_dict: # check if the molecule has any windows: if result_dict[molecule][1]['diameters'] is None: continue # add cage COM cage_com = ase.Atom(symbol='Ne', position=result_dict[molecule][0]) structure.append(cage_com) # add window COMs: for wCOM in result_dict[molecule][1]['centre_of_mass']: window_com = ase.Atom(symbol='He', position=wCOM) structure.append(window_com) # add optimized cage pore COM pore_com = ase.Atom(symbol='Ar', position=result_dict[molecule][2]) structure.append(pore_com) # output to CIF output = file.replace(suffix, '_appended.cif') structure.write(output, format='cif') output = file.replace(suffix, '_appended.pdb') structure.write(output)
def randomCluster(n): atoms = ase.Atoms() atoms.append(ase.Atom('H', [0,0,0])) for i in range(n-1): farthest = 1e300 a = numpy.random.normal(0, 1, 3) a = n * a/numpy.linalg.norm(a) A = numpy.array([0,0,0]) - a Au = A/numpy.linalg.norm(A) A = 2*n*Au for atom in atoms: b = atom.position B = b - a C = Au * numpy.dot(B, Au) D = b - (a + C) Dm = numpy.linalg.norm(D) Q = elements['H']['radius'] + elements[atom.symbol]['radius'] if Dm > Q: continue if Dm == 0: V = Q else: V = math.sqrt((Q*Q) - (Dm*Dm)) farthest = min(numpy.linalg.norm(C)-V, farthest) p = a + Au * farthest atoms.append(ase.Atom('H', p)) return atoms
def broadened_linescan(self, start, end, width, threshold, points=100, nwidth=10, bottom=0.0, getlines=False): """ Make data linescan between start and end points with effective 'width' for data scanner. Not: only x- and y-coordinates of the start and end points matter. Line scan between start and end, but with such a way that you perform 'nwidth' parallel line scans from width/2 distance from both sides of the original line. The result with given distance from the start is the maximum over all parallel values. Parameters: ----------- start: position array end: position array width: width (in Angstrom) for data scanning threshold: constant-data contour line threshold nwidth: how many parallel line scans are performed points: linear interpolation in output using this many points. getlines: if True, return ase.Atoms object where atoms are 'X's with starting and end-points of the line scans Return: distance array and heights on that distance array (if getlines, return also the ase.Atoms object) """ start, end = vec(start), vec(end) n = np.cross(end - start, vec([0, 0, 1])) n /= np.linalg.norm(n) start0, end0 = start - (width / 2) * n, end - (width / 2) * n atoms = ase.Atoms() # perform nwidth parallel scans hlist = [] for shift in np.linspace(0, width, nwidth): l, h = self.linescan(start0 + shift * n, end0 + shift * n, threshold, points=points, bottom=bottom) atoms.append(ase.Atom('X', start0 + shift * n)) atoms.append(ase.Atom('X', end0 + shift * n)) hlist.append(h) hlist = np.array(hlist) # take maxima from these scans h = [] for i in range(len(l)): h.append(max(hlist[:, i])) if getlines: return l, h, atoms else: return l, h
def get_graphene_structure(acc=1.42, distance=3.35): """ Create ase.Atoms object for graphene """ cell = np.array([[acc * 0.5 * np.sqrt(3), -acc * 1.5, 0.0], [acc * 0.5 * np.sqrt(3), acc * 1.5, 0.0], [0.0, 0.0, distance]]) atoms = ase.Atoms(cell=cell, pbc=[True, True, True]) scaled_positions = np.array([[1. / 3., 2. / 3., 0.5], [2. / 3., 1. / 3., 0.5]]) positions = np.dot(scaled_positions, cell) atoms.append(ase.Atom(symbol="C", position=positions[0])) atoms.append(ase.Atom(symbol="C", position=positions[1])) atoms.wrap() return atoms
def _superpose_next_intercalated_layer(block, natoms_layer=None): """ Parameters ----------- block : ase.Atoms object structure on which a molecule is put on graphite natoms_layer : integer number of C atoms in a layer """ ## vector for the displacement of the next block ibase = 0 center_hex = _get_center_of_a_hexagon(block[:natoms_layer], ibase=ibase) disp = center_hex - block[0].position + block.cell[2, :] ## prepare the new cell block2 = block.copy() block2.cell[2, 2] *= 2 ## displacement vector for the next block disp = block[natoms_layer].position - block[0].position disp[2] = block.cell[2, 2] ## superpose the next block for ia in range(len(block)): block2.append( ase.Atom(symbol=block[ia].symbol, position=block[ia].position + disp)) return block2
def soaper(structure, positions): structure = structure.copy() for i in range(len(positions)): structure.append( ase.Atom(position=tuple(positions[i]), symbol=tracer_atomic_number)) return _soap(soap_cmd_line, structure, quip_path=quip_path)
def create_ase_ts_geometry(self): mol_list = AllChem.MolToMolBlock(self.rdkit_ts).split('\n') ase_atoms = [] for i, line in enumerate(mol_list): if i > 3: try: atom0, atom1, bond, rest = line atom0 = int(atom0) atom0 = int(atom1) bond = float(bond) except ValueError: try: x, y, z, symbol = line.split()[0:4] x = float(x) y = float(y) z = float(z) ase_atoms.append( ase.Atom(symbol=symbol, position=(x, y, z))) except: continue self.ase_ts = ase.Atoms(ase_atoms)
def get_pubchem_structure(cid=24380): """ Parameter ------------- cid : integer PubChem ID Return ---------- mol : Atoms object """ c = pcp.Compound.from_cid(cid) mol = ase.Atoms() natoms = len(c.elements) mol.number_of_atoms = len(c.elements) for ia in range(natoms): el = c.elements[ia] coord = np.zeros(3) coord[0] = c.record['coords'][0]['conformers'][0]['x'][ia] coord[1] = c.record['coords'][0]['conformers'][0]['y'][ia] if c.coordinate_type.lower() == "2d": coord[2] = 0. else: coord[2] = c.record['coords'][0]['conformers'][0]['z'][ia] mol.append(ase.Atom(symbol=el, position=coord)) mol.wrap() return mol
def _get_superposed_structure(gra, mol, distance=3.0, tgra=3.35, iax=2, tol=1e-5): for j in range(3): if j == iax: continue if np.linalg.norm(gra.cell[j] - mol.cell[j]) > tol: print("Error") exit() ## get positions zgra_max = np.max(gra.positions[:, iax]) zmol_min = np.min(mol.positions[:, iax]) zmol_max = np.max(mol.positions[:, iax]) tmol = zmol_max - zmol_min ## translate vector for the molecule disp_mol = np.array([0., 0., zgra_max - zmol_min + distance]) ## adjust cell size zheight = gra.cell[iax, iax] - tgra + 2. * distance + tmol gra.cell[iax, iax] = zheight ## superpose gic = ase.Atoms(cell=gra.cell, pbc=[True, True, True]) for atom in gra: gic.append(atom) for atom in mol: gic.append( ase.Atom(symbol=atom.symbol, position=atom.position + disp_mol)) return gic
def surrogate_features(self, observations: List[ObservationType], focus: torch.Tensor, element: torch.Tensor, distance: torch.Tensor, angle: torch.Tensor, dihedral: torch.Tensor) -> torch.Tensor: features = torch.zeros(size=(len(observations), self.num_afeats), dtype=torch.float32, device=self.device) focus = to_numpy(focus) element = to_numpy(element) distance = to_numpy(distance) angle = to_numpy(angle) dihedral = to_numpy(dihedral) for i, observation in enumerate(observations): atoms, _ = self.observation_space.parse(observation) positions = [atom.position for atom in atoms] new_position = zmat.position_atom_helper( positions=positions, focus=int(round(focus[i, 0])), distance=distance[i, 0], angle=angle[i, 0], dihedral=dihedral[i, 0], ) new_element = int(round(element[i, 0])) new_atom = ase.Atom( symbol=self.observation_space.bag_space.get_symbol( new_element), position=new_position) atoms.append(new_atom) features[i] = self.embedding_fn(self.converter(atoms))[:, -1, :] return features
def remove_solvent(pw_struct, ASE_struct, mol_list): """ Remove solvents and write desolvated structure to ASE_struct. Keyword Arguments: pw_struct (pyWindow Rebuilt Molecule) - structure to analyze molecules of ASE_struct (ASE.Atoms()) - structure to append non-solvent atoms to mol_list (list) - list of distinct molecules from pyWindow modularize Returns: ASE_struct_out (ASE.Atoms()) - structure with non-solvent atoms """ # make deep copy of ASE_struct ASE_struct_out = copy.deepcopy(ASE_struct) for molecule in pw_struct.molecules: logging.info(f'Analysing molecule {molecule + 1} out of ' f'{len(pw_struct.molecules)}') mol = pw_struct.molecules[molecule] if is_solvent(molecule=mol) is False: logging.info(f'is NOT solvent with {mol.no_of_atoms} atoms') # append atoms to ASE_struct_out atom_ids = np.arange(1, mol.no_of_atoms + 1) coords = mol.coordinates atom_symbs = mol.atom_ids for i, j, k in zip(atom_ids, atom_symbs, coords): curr_atm = ase.Atom(symbol=j, position=k, index=i) ASE_struct_out.append(curr_atm) return ASE_struct_out
def ase_atoms_from_pw_out(pw_out_file): with open(pw_out_file, 'r') as f: contents = f.read() final_coords_str = re.search( "Begin final coordinates\n([\s\S]*)End final coordinates", contents).group(1) atoms = ase.Atoms() for line in final_coords_str.split("\n"): sp = line.split() if len(sp) == 4: atoms.append(ase.Atom(sp[0], np.array(sp[1:], dtype=float))) celldm1 = float( re.search("celldm\(1\)=(.*)celldm\(2\)=", contents).group(1)) cell_str = re.search("crystal axes:.*\n([\s\S]*)reciprocal axes", contents).group(1) cell = [] for line in cell_str.split("\n"): sp = line.split() if len(sp) == 7: cell += sp[3:6] cell = np.array(cell, dtype=float).reshape((3, 3)) * celldm1 / ang_2_bohr atoms.cell = cell atoms.pbc = True return atoms
def ase_atoms(crystal, **kwargs): """ Convert a :class:`crystals.Crystal` object into an :class:`ase.Atoms` object. Keyword arguments are passed to :class:`ase.Atoms` constructor. Parameters ---------- crystal : :class:`Crystal` Crystal to be converted. Returns ------- atoms : ase.Atoms Group of atoms ready for ASE's routines. Raises ------ ImportError : If ASE is not installed """ if not WITH_ASE: raise ImportError("ASE is not installed/importable.") return ase.Atoms( symbols=[ ase.Atom( symbol=atom.element, position=atom.coords_cartesian, magmom=atom.magmom, mass=atom.mass, ) for atom in crystal ], cell=np.array(crystal.lattice_vectors), **kwargs, )
def get_ase_mol(self): """ A method for creating an ase atoms object from an rdkit mol """ if not self.rdkit_molecule: self.get_rdkit_mol() mol_list = rdkit.Chem.AllChem.MolToMolBlock( self.rdkit_molecule).split('\n') ase_atoms = [] for i, line in enumerate(mol_list): if i > 3: try: atom0, atom1, bond, rest = line atom0 = int(atom0) atom0 = int(atom1) bond = float(bond) except ValueError: try: x, y, z, symbol = line.split()[0:4] x = float(x) y = float(y) z = float(z) ase_atoms.append( ase.Atom(symbol=symbol, position=(x, y, z))) except BaseException: continue self._ase_molecule = ase.Atoms(ase_atoms) return self.ase_molecule
def get_stacking_graphene(na=1, nb=1, nc=1, distance=3.35): """ Get ase.Atoms object for an AB stacking graphite """ graphene = get_graphene_structure(distance=distance) ## make a supercell along x and y directions sc = make_supercell(graphene, [[na, 0, 0], [0, nb, 0], [0, 0, 1]]) natoms_layer = len(sc) ## make a supercell along z direction graphite = ase.Atoms(cell=[sc.cell[0], sc.cell[1], sc.cell[2] * nc], pbc=[True, True, True]) elements = ['C', 'C'] for iz in range(nc): ## displacment to form AB stacking disp = np.zeros(3) if iz % 2 == 1: disp += (graphene.cell[0, :] + graphene.cell[1, :] * 2.) * 2. / 3. disp += sc.cell[2, :] * iz ## add atoms at the layer for ia in range(len(sc)): graphite.append( ase.Atom(symbol=elements[iz % 2], position=sc.positions[ia, :] + disp, tag=iz % 2 + 1)) ## graphite.wrap() return graphite
def plot_centres_xsf(structure,w90_calc): a = structure.get_ase() new_a = a.copy() out = w90_calc.out.output_parameters.get_dict()['wannier_functions_output'] coords = [i['coordinates'] for i in out] for c in coords: new_a.append(ase.Atom('X',c)) new_a.write('./wannier.xsf')
def migration_prep(self): sz = 16 perf_atoms = self.set_bcc_convention(size=[sz, sz, sz]) vect = np.array([1, 1, 1]) * self.pot['lattice'] pos1 = vect * sz * 0.5 pos2 = vect * sz * 0.5 + 0.5 * vect pos3 = vect * 0.0 dellist = [] atoms = perf_atoms.copy() for atom in atoms: if np.isclose(pos1 - atom.position, np.array([0, 0, 0])).all() or \ np.isclose(pos2 - atom.position, np.array([0, 0, 0])).all() or \ np.isclose(pos3 - atom.position, np.array([0, 0, 0])).all(): dellist.append(atom.index) print(dellist) del atoms[dellist] atoms1 = atoms.copy() atoms2 = atoms.copy() atoms1.append(ase.Atom('Nb', pos1)) # atoms1.append(ase.Atom('Nb', pos3)) # set this atom to be other type so we can fix it in lammps atoms1.append(ase.Atom('W', pos3)) atoms2.append(ase.Atom('Nb', pos2)) # atoms2.append(ase.Atom('Nb', pos3)) atoms2.append(ase.Atom('W', pos3)) # for vasp self.write_poscar_fix(atoms1, "posi") # change it manually then self.write_poscar_fix(atoms2, "posf") # for md system, elements = am.convert.ase_Atoms.load(atoms1) lmp.atom_data.dump(system, "init.txt") shutil.copy("init.txt", "init0.txt") system, elements = am.convert.ase_Atoms.load(atoms2) lmp.atom_data.dump(system, "final.txt") shutil.copy("final.txt", "init1.txt")
def get_atoms_obj(self): """ Builds NP in the form of a Cu NP ase.Atoms object - stores under self.atoms_obj property - returns atoms_obj """ if self._atoms_obj is None: self._atoms_obj = ase.Atoms( [ase.Atom('Cu', (i.x, i.y, i.z)) for i in self.atoms]) return self._atoms_obj
def Atoms(self): """ convert to ase object """ import ase mu = pb.Molecule(self.m) m2 = ase.Atoms([]) for ai in mu.atoms: m2.append(ase.Atom(ai.atomicnum, ai.coords)) return m2
def to_ase(self): cell = self.content['cell'] atoms = [ ase.Atom(site[0], tuple(site[1])) for site in self.content['positions'] ] aseobj = ase.Atoms(atoms) aseobj.set_cell(cell) aseobj.set_pbc(self.content['periodicity']) return aseobj
def plot_centres_xsf(structure, w90_calc, filename='./wannier.xsf'): """ Plots Wannier function centres in .xsf format """ a = structure.get_ase() new_a = a.copy() out = w90_calc.out.output_parameters.get_dict()['wannier_functions_output'] coords = [i['wf_centres'] for i in out] for c in coords: new_a.append(ase.Atom('X', c)) new_a.write(filename)
def read_bopfox(filename): f = open(filename,'r') lines = f.readlines() f.close() line_index = 0 newlines = [] # strip out comment lines for line in lines: l = line.strip() if len(l) < 1: continue if l.startswith("/"): continue if l.startswith("#"): continue newlines.append(l) lines = newlines a = ase.Atoms() box = numpy.zeros((3,3)) coord = "cartesian" scale = 1.0 while line_index < len(lines): l = lines[line_index] if "magnetisation" in l: break if "=" in l: key = l.split("=")[0].strip() if key == "StrucName": pass elif key == "aLat": scale = float(l.split("=")[1].strip()) elif key == "a1": box[0] = [float(i) for i in l.split("=")[1].strip().split()] elif key == "a2": box[1] = [float(i) for i in l.split("=")[1].strip().split()] elif key == "a3": box[2] = [float(i) for i in l.split("=")[1].strip().split()] elif key == "coord": coord = l.split("=")[1].strip() else: atomdata = l.strip().split() symbol = atomdata[0] x, y, z = float(atomdata[1]), float(atomdata[2]), float(atomdata[3]) a.append(ase.Atom(symbol, (x, y, z))) line_index += 1 a.cell = box * scale if coord == "direct": for i in range(len(a)): a.positions[i] = numpy.dot(a.positions[i], a.cell) else: for i in range(len(a)): a.positions[i] *= scale return a
def setElsProps(self): for e in self.setting['elements']: a = ase.Atom(e) mass = a.mass / _Nav number = a.number form = pt.formula(a.symbol) e_ = form.structure[0][1] crys = e_.crystal_structure['symmetry'] a_ = e_.crystal_structure['a'] self.elsProps.append({'ase':a, 'mass': mass, 'structure': crys, 'a':a_ , 'number':number})
def check_dissociated(self, cutoff=1.2): """Check if adsorbate dissociates""" dissociated = False if not len(self.B) > self.nslab + 1: # only one adsorbate return dissociated adsatoms = [atom for atom in self.B[self.nslab:]] ads0, ads1 = set(atom.symbol for atom in adsatoms) bond_dist = get_ads_dist(self.B, ads0, ads1) Cradii = [ cradii[atom.number] for atom in [ase.Atom(ads0), ase.Atom(ads1)] ] bond_dist0 = sum(Cradii) if bond_dist > cutoff * bond_dist0: print('DISSOCIATED: {} Ang > 1.2 * {} Ang'.format( bond_dist, bond_dist0)) dissociated = True return dissociated
def plot_centres_xsf(structure, w90_calc, filename='./wannier.xsf'): """ Plots Wannier function centres in .xsf format """ # Disabling the import-error since this is an optional requirement import ase # pylint: disable=import-error a = structure.get_ase() new_a = a.copy() out = w90_calc.out.output_parameters.get_dict()['wannier_functions_output'] coords = [i['wf_centres'] for i in out] for c in coords: new_a.append(ase.Atom('X', c)) new_a.write(filename)
def _structure_to_atoms(self) -> Atoms: """ Returns the structure as an ASE Atoms object. Returns ------- atomic configuration """ import ase conf = ase.Atoms(pbc=self.pbc) conf.set_cell(self.cell) for symbol, position in zip(self.chemical_symbols, self.positions): conf.append(ase.Atom(symbol, position)) return conf
def launch(box_size, dimer_separation, firstdimer_elements, seconddimer_elements, structure_group_label, structure_group_description, dryrun): """ Script for creating surface structures for a given size and matrix element. Generates a set of structures with varying vacuum thickness """ if not dryrun: structure_group = Group.objects.get_or_create( label=structure_group_label, description=structure_group_description)[0] else: structure_group = None box_size = float(box_size) extras = {'box_size': box_size} base_structure = ase.Atoms(cell=([box_size, box_size, box_size]), pbc=True) seperation_distances = get_displacements_array(dimer_separation) firstdimer_elements = prep_elementlist(firstdimer_elements) seconddimer_elements = prep_elementlist(seconddimer_elements) previous_firstdimer_elements = [ ] # to avoid duplication in generated structures for firstdimer_element in firstdimer_elements: dimer_structure = base_structure.copy() # create and store single atom version first_atom = ase.Atom(firstdimer_element) dimer_structure.append(first_atom) extras['firstdimer_element'] = firstdimer_element extras['second_element'] = "" extras['atomatom_distance'] = "" store_asestructure(dimer_structure, extras, structure_group, dryrun) dimer_structure.append(first_atom) #This will be changed later for seconddimer_element in seconddimer_elements: dimer_structure[1].symbol = seconddimer_element if seconddimer_element in previous_firstdimer_elements: continue extras['second_element'] = seconddimer_element for distance in seperation_distances: dimer_structure[1].position[0] = distance extras['atomatom_distance'] = distance store_asestructure(dimer_structure, extras, structure_group, dryrun) previous_firstdimer_elements += [firstdimer_element]
def read_aims(filename): f = open(filename) atoms = ase.Atoms() l = 0 cell = numpy.zeros((3, 3)) for line in f: line = line[:line.find('#')] line = line.strip() if len(line) == 0: continue fields = line.split() if fields[0] == 'lattice_vector': cell[l, 0] = float(fields[1]) cell[l, 1] = float(fields[2]) cell[l, 2] = float(fields[3]) l += 1 if l == 3: atoms.set_cell(cell) print cell if fields[0] == 'atom': pos = numpy.array( (float(fields[1]), float(fields[2]), float(fields[3]))) element = fields[4] atoms.append(ase.Atom(element, position=pos)) if fields[0] == 'atom_frac': scaled_pos = numpy.array( (float(fields[1]), float(fields[2]), float(fields[3]))) pos = numpy.dot(cell, scaled_pos) element = fields[4] atoms.append(ase.Atom(element, position=pos)) f.close() return atoms
def get_gic_structure(nprim=[2, 2, 1], molecule=None, distance=3.0, layer_distance=3.35, set_nemdtag=True): """ Create a graphene intercalation compund Parameters ------------- distance : float, unit=[A] distance between the molecule and graphite layer """ ## make a graphtie structure graphite = get_stacking_graphene(na=nprim[0], nb=nprim[1], nc=nprim[2], distance=layer_distance) ## center of a hexagonal lattice in the top layer natoms_layer = int(len(graphite) / nprim[2]) center_hex = _get_center_of_a_hexagon(graphite[-natoms_layer:]) ## get the center of the molecule center_mol = np.zeros(3) for j in range(3): center_mol[j] += np.average(molecule.get_positions()[:, j]) ## put a molecule on the center of the hexagonal lattice ## Be careful for the z-position disp = center_hex + np.array([0, 0, distance]) - center_mol intercalate = graphite.copy() intercalate.cell[2, 2] += distance * 2.0 - layer_distance for ia in range(len(molecule)): intercalate.append( ase.Atom(symbol=molecule[ia].symbol, position=molecule[ia].position + disp)) ## If the number of graphene layers is even, the position of the next layers ## should be adjusted. if nprim[2] % 2 == 0: intercalate = _superpose_next_intercalated_layer( intercalate, natoms_layer=natoms_layer) ## _set_element_center(intercalate, element="Fe") ## set tag for NEMD simulation if set_nemdtag: set_tags4md_structure(intercalate) return intercalate
def _get_ase_atoms(cjson_atoms): elements = cjson_atoms.get('elements', {}) number = elements.get('number') if number is None: symbol = elements.get('symbol') if symbol is None: raise Exception('Atomic numbers are missing.') number = list(map(lambda sym: ase.data.atomic_numbers[sym], symbol)) n_atoms = len(number) positions = cjson_atoms.get('coords', {}).get('3d', []) if len(positions) != 3 * n_atoms: raise Exception('Atomic positions are missing.') atoms = [] for i in range(n_atoms): atoms.append(ase.Atom(number[i], positions[i * 3:i * 3 + 3])) return atoms