def prepare_ga(dbfile='godb.db', splits={(2,): 1}, N=20): blocks = [('Pd', 4), ('OH', 8)] # the building blocks volume = 50. * 4 # volume in angstrom^3 l = [list(Atoms(block).numbers)*count for block, count in blocks] stoichiometry = [item for sublist in l for item in sublist] atom_numbers = list(set(stoichiometry)) blmin = closest_distances_generator(atom_numbers=atom_numbers, ratio_of_covalent_radii=0.6) blmin[(1, 8)] = blmin[(8, 1)] = 2.0 cellbounds = CellBounds(bounds={'phi': [0.2 * 180., 0.8 * 180.], 'chi': [0.2 * 180., 0.8 * 180.], 'psi': [0.2 *180., 0.8 * 180.], 'a': [2, 8], 'b': [2, 8], 'c': [2, 8]}) # create the starting population sg = StartGenerator(blocks, blmin, volume, cellbounds=cellbounds, splits=splits) # create the database to store information in da = PrepareDB(db_file_name=dbfile, stoichiometry=stoichiometry) for i in range(N): a = sg.get_new_candidate() a.set_initial_magnetic_moments(magmoms=None) niggli_reduce(a) da.add_unrelaxed_candidate(a) return
def __init__(self, atoms, kpts=(1, 1, 1), label='cp2k_run', run_type=None, **extra_cp2k_kwargs): try: niggli_reduce(atoms) except RuntimeError: pass kwargs = {k: None for k in CP2K.default_parameters} kwargs['debug'] = False kwargs['potential_file'] = 'GTH_POTENTIALS' kwargs['pseudo_potential'] = 'GTH-PBE' kwargs['basis_set_file'] = 'BASIS_MOLOPT' kwargs['basis_set'] = 'DZVP-MOLOPT-SR-GTH' if type(kpts) == float or type(kpts) == int: mp = kptdensity2monkhorstpack(atoms, kptdensity=kpts, even=False) kpts = tuple(mp) inp = template.replace('__MPMESH__', ' '.join(map(str, kpts))) kwargs['inp'] = inp kwargs.update(extra_cp2k_kwargs) CP2K.__init__(self, atoms=atoms, label=label, **kwargs)
def relax(atoms, cellbounds=None): # Performs a variable-cell relaxation of the structure calc = EMT() atoms.set_calculator(calc) converged = False niter = 0 while not converged and niter < 10: if cellbounds is not None: cell = atoms.get_cell() if not cellbounds.is_within_bounds(cell): niggli_reduce(atoms) cell = atoms.get_cell() if not cellbounds.is_within_bounds(cell): # Niggli reduction did not bring the unit cell # within the specified bounds; this candidate should # be discarded so we set an absurdly high energy finalize(atoms, 1e9) return ecf = ExpCellFilter(atoms) dyn = FIRE(ecf, maxmove=0.2, logfile=None, trajectory=None) dyn.run(fmax=1e-3, steps=100) converged = dyn.converged() niter += 1 dyn = FIRE(atoms, maxmove=0.2, logfile=None, trajectory=None) dyn.run(fmax=1e-2, steps=100) e = atoms.get_potential_energy() f = atoms.get_forces() s = atoms.get_stress() finalize(atoms, energy=e, forces=f, stress=s)
def nigglixyzfunc(name, cellABCabc): a = read(name) a.set_cell(cellABCabc) a.set_pbc(True) niggli_reduce(a) minimize_tilt(a, order=range(0, 3), fold_atoms=True) return [a.get_cell(), a.get_chemical_symbols(), a.get_positions()]
def test_niggli(i): cell = cells_in[i] conf.set_cell(cell) niggli_reduce(conf) cell = conf.get_cell() diff = np.linalg.norm(cell - cells_out[i]) assert diff < 1e-5, \ 'Difference between unit cells is too large! ({0})'.format(diff)
def finalize(atoms, energy=None, forces=None, stress=None): niggli_reduce(atoms) atoms.wrap() calc = SinglePointCalculator(atoms, energy=energy, forces=forces, stress=stress) atoms.calc = calc raw_score = -atoms.get_potential_energy() set_raw_score(atoms, raw_score)
def write_permutations_to_db(db_name, ref_xyz_file, symbols): atoms = read(ref_xyz_file) niggli_reduce(atoms) db = connect(db_name) for symb_set in symbols: for i, symb in enumerate(symb_set): atoms[i].symbol = symb db.write(atoms) print("All intermetallic structures written to {}".format(db_name))
def calculate(self, atoms=None, properties=None, system_changes=all_changes): try: niggli_reduce(atoms) except RuntimeError: pass CP2K.calculate(self, atoms, properties, system_changes)
def test_attempt_supercell(get_supercell_paths): atoms1 = read(get_supercell_paths[0]) atoms2 = read(get_supercell_paths[1]) niggli_reduce(atoms1) niggli_reduce(atoms2) a_1, a_2 = attempt_supercell(atoms1, atoms2) assert pytest.approx(a_1.get_cell_lengths_and_angles(), 0.001) == a_2.get_cell_lengths_and_angles()
def create_convergence_database(db_name): atoms = read("data/al3mg2_ref.xyz") niggli_reduce(atoms) atoms[0].symbol = "Mg" atoms[1].symbol = "Mg" db = connect(db_name) kpt = [4, 6, 8, 10, 12, 14] for N in kpt: db.write(atoms, kpt=N) print("Convergence study written to {}".format(db_name))
def main(fxyz, prefix, stride): # read frames if fxyz != 'none': frames = read(fxyz, ':') nframes = len(frames) print("read xyz file:", fxyz, ", a total of", nframes, "frames") for s in range(0, nframes, stride): frame = frames[s] niggli_reduce(frame) minimize_tilt(frame, order=range(0, 3), fold_atoms=True) write(prefix + '-' + str(s) + '.res', frame)
def main(runId): db = connect(DB_NAME) row = db.get(id=runId) group = row.group atoms = row.toatoms() niggli_reduce(atoms) calc = EMT() atoms.set_calculator(calc) ucell = UnitCellFilter(atoms) opt = PreconLBFGS(ucell) opt.run(fmax=0.02, smax=0.003) db.write(atoms, group=group, struct_type='relaxed')
def parse_periodic_case(file_1, file_2, try_supercell: bool = True, pymatgen: bool = False, get_reduced_structure: bool = True): """ Parser for periodic structures, handles two possible cases: (1) Structures are supercells (within tolerance), then one cell is multiplied by the scaling factors (2) Structures are not supercells of each other, then we rescale on cell to the volume of the other cell to make sure we have meaningful comparisons. Args: file_1 (str/pymatgen structure object): path to first file, in on format that ASE can parse, pymatgen structure object in case pymatgen=True file_2 (str/pymatgen structure object): path to second file, pymatgen structure object in case pymatgen=True try_supercell (bool): if true, we attempt to build a supercell, default: True pymatgen (bool): if true, then file_1 and file_2 take pymatgen structure objects get_reduced_structure (bool): if true (default) it gets the Niggli reduced cell. Returns: atomic symbols (list), cartesian positions (list) of structure 1, atomic symbols (list), cartesian positions (list) of structure 2 """ if pymatgen: atoms1 = AseAtomsAdaptor.get_atoms(file_1) atoms2 = AseAtomsAdaptor.get_atoms(file_2) else: atoms1 = read(file_1) atoms2 = read(file_2) if get_reduced_structure: niggli_reduce(atoms1) niggli_reduce(atoms2) if try_supercell: a1, a2 = attempt_supercell(atoms1, atoms2) else: a1, a2 = rescale_periodic_system(atoms1, atoms2) atomic_symbols_1 = a1.get_chemical_symbols() positions_1 = a1.get_positions() atomic_symbols_2 = a2.get_chemical_symbols() positions_2 = a2.get_positions() return np.array(atomic_symbols_1), np.array(positions_1), np.array( atomic_symbols_2), np.array(positions_2)
def parse_periodic_case(file_1, file_2): atoms1 = read(file_1) atoms2 = read(file_2) niggli_reduce(atoms1) niggli_reduce(atoms2) a1, a2 = rescale_periodic_system(atoms1, atoms2) atomic_symbols_1 = a1.get_chemical_symbols() positions_1 = a1.get_positions() atomic_symbols_2 = a2.get_chemical_symbols() positions_2 = a2.get_positions() return atomic_symbols_1, positions_1, atomic_symbols_2, positions_2
def dcdft(): """Create delta-codes-DFT collection. Data from: https://github.com/molmod/DeltaCodesDFT """ os.environ['USER'] = '******' con = ase.db.connect('dcdft.json') with open('history/exp.txt') as fd: lines = fd.readlines() experiment = {} for line in lines[2:-1]: words = line.split() print(words) experiment[words[0]] = [float(word) for word in words[1:]] with open('WIEN2k.txt') as fd: lines = fd.readlines() for line in lines[2:73]: words = line.split() symbol = words.pop(0) vol, B, Bp = (float(x) for x in words) filename = 'primCIFs/' + symbol + '.cif' atoms = read(filename) if symbol in ['Li', 'Na']: niggli_reduce(atoms) M = { 'Fe': 2.3, 'Co': 1.2, 'Ni': 0.6, 'Cr': 1.5, 'O': 1.5, 'Mn': 2.0 }.get(symbol) if M is not None: magmoms = [M] * len(atoms) if symbol in ['Cr', 'O', 'Mn']: magmoms[len(atoms) // 2:] = [-M] * (len(atoms) // 2) atoms.set_initial_magnetic_moments(magmoms) extra = {} exp = experiment.get(symbol, []) for key, val in zip(['exp_volume', 'exp_B', 'exp_Bp'], exp): extra[key] = val con.write(atoms, name=symbol, wien2k_B=B, wien2k_Bp=Bp, wien2k_volume=vol, **extra)
def get_reduced_structure(self, structure): sname = Path(structure).name stem = Path(structure).stem if self.cached: self.reduced_structure_dict = {} try: # Cif reader in ASE seems more stable to me, especially for CSD data atoms = read(structure) except Exception: logger.error("Could not read structure %s", stem) else: niggli_reduce(atoms) if not self.cached: write(os.path.join(self.tempdirpath, sname), atoms) else: crystal = AseAtomsAdaptor.get_structure(atoms) self.reduced_structure_dict[stem] = crystal return stem
def dcdft(): """Create delta-codes-DFT collection. Data from: https://github.com/molmod/DeltaCodesDFT """ os.environ['USER'] = '******' con = ase.db.connect('dcdft.json') with open('history/exp.txt') as fd: lines = fd.readlines() experiment = {} for line in lines[2:-1]: words = line.split() print(words) experiment[words[0]] = [float(word) for word in words[1:]] with open('WIEN2k.txt') as fd: lines = fd.readlines() for line in lines[2:73]: words = line.split() symbol = words.pop(0) vol, B, Bp = (float(x) for x in words) filename = 'primCIFs/' + symbol + '.cif' atoms = read(filename) if symbol in ['Li', 'Na']: niggli_reduce(atoms) M = {'Fe': 2.3, 'Co': 1.2, 'Ni': 0.6, 'Cr': 1.5, 'O': 1.5, 'Mn': 2.0}.get(symbol) if M is not None: magmoms = [M] * len(atoms) if symbol in ['Cr', 'O', 'Mn']: magmoms[len(atoms) // 2:] = [-M] * (len(atoms) // 2) atoms.set_initial_magnetic_moments(magmoms) extra = {} exp = experiment.get(symbol, []) for key, val in zip(['exp_volume', 'exp_B', 'exp_Bp'], exp): extra[key] = val con.write(atoms, name=symbol, wien2k_B=B, wien2k_Bp=Bp, wien2k_volume=vol, **extra)
def mutate(self, atoms): """ Does the actual mutation. """ cell_ref = atoms.get_cell() pos_ref = atoms.get_positions() vol = atoms.get_volume() if self.use_tags: tags = atoms.get_tags() gather_atoms_by_tag(atoms) pos = atoms.get_positions() mutant = atoms.copy() if self.cellbounds is not None: if not self.cellbounds.is_within_bounds(cell_ref): niggli_reduce(mutant) count = 0 too_close = True maxcount = 1000 while too_close and count < maxcount: mutant.set_cell(cell_ref, scale_atoms=False) mutant.set_positions(pos_ref) # generating the strain matrix: strain = np.identity(3) for i in range(3): for j in range(i + 1): if i == j: strain[i, j] += gauss(0, self.stddev) else: epsilon = 0.5 * gauss(0, self.stddev) strain[i, j] += epsilon strain[j, i] += epsilon # applying the strain: cell_new = np.dot(strain, cell_ref) # volume scaling: v = abs(np.linalg.det(cell_new)) if self.scaling_volume is None: cell_new *= (vol / v)**(1. / 3) else: cell_new *= (self.scaling_volume / v)**(1. / 3) # check cell dimensions: if not self.cellbounds.is_within_bounds(cell_new): continue if self.use_tags: transfo = np.linalg.solve(cell_ref, cell_new) for tag in np.unique(tags): select = np.where(tags == tag) cop = np.mean(pos[select], axis=0) disp = np.dot(cop, transfo) - cop mutant.positions[select] += disp mutant.set_cell(cell_new, scale_atoms=not self.use_tags) # check distances: too_close = atoms_too_close(mutant, self.blmin, use_tags=self.use_tags) count += 1 if count == maxcount: mutant = None return mutant
[-4.47766735594495e+00, +1.26866266221366e+01, +0.00000000000000e+00], [-3.68163760377696e+00, -5.94997793843316e+00, +1.14910098375475e+01]], [[+1.13578166916005e+01, +0.00000000000000e+00, +0.00000000000000e+00], [-4.62236725820948e+00, +1.28309672640153e+01, +0.00000000000000e+00], [-3.36772471669551e+00, -6.41548363200768e+00, +1.15542200082913e+01]], [[+1.18321595661992e+01, +0.00000000000000e+00, +0.00000000000000e+00], [-4.71877792223422e+00, +1.29511827614560e+01, +0.00000000000000e+00], [-3.55669082198251e+00, -6.47559138072800e+00, +1.16368667031408e+01]], [[+4.81947971142972e-03, +0.00000000000000e+00, +0.00000000000000e+00], [+4.12397039845618e-03, +4.86743859122682e+01, +0.00000000000000e+00], [+4.62732595971025e-03, +1.13797841621313e+01, +6.81149615940608e+01]], [[+1.43683914413843e-01, +0.00000000000000e+00, +0.00000000000000e+00], [+4.73841211849216e-02, +8.02075186538656e+00, +0.00000000000000e+00], [+9.29303317118020e-03, +8.28854375915883e-01, +1.93660401476964e+01]], [[+5.02420000000000e+00, +0.00000000000000e+00, +0.00000000000000e+00], [-2.40035596861745e+00, +1.25083680303996e+01, +0.00000000000000e+00], [-2.37319883118274e+00, -5.49894680458153e+00, +2.86098306766757e+01]], [[+5.02419976114664e+00, +0.00000000000000e+00, +0.00000000000000e+00], [-2.40036499209593e+00, +1.25083662987906e+01, +0.00000000000000e+00], [-2.37320481266200e+00, -5.49892622854049e+00, +2.86097847514890e+01]]]) conf = Atoms(pbc=True) for i, cell in enumerate(cells_in): conf.set_cell(cell) niggli_reduce(conf) cell = conf.get_cell() diff = np.linalg.norm(cell - cells_out[i]) assert diff < 1e-5, \ 'Difference between unit cells is too large! ({0})'.format(diff)
def __init__(self, fxyz=None, stride=1, periodic=True, fileformat=None): # compile a list of matching xyz files # in fact they don't strictly need to be xyz format, anything that can be read by ASE is fine # a list of possible file formats: https://wiki.fysik.dtu.dk/ase/ase/io/io.html if '*' in fxyz: self.fxyz = glob.glob(fxyz) print("Find matching input files with coordinates: ", self.fxyz) else: self.fxyz = fxyz # essential self.stride = stride self.periodic = periodic if fileformat is not None: import ast self.fileformat = ast.literal_eval(fileformat) else: self.fileformat = {} # store the xyz file self.frames = None self.nframes = 0 self.natom_list = [] # number of atoms for each frame self.total_natoms = 0 # total number of atoms for all frames self.global_species = [] # list of elements contains in all frames # record the state of the computation, e.g. which descriptors have been computed self.computed_desc_dict = {'data': {'fxyz': fxyz}} self.computed_desc_dict = {'descriptors': {}} # the conversion between tag of the descriptors and their acronyms self.tag_to_acronym = {'global': {}, 'atomic': {}} # we make a dictionary to store the computed descriptors self.global_desc = {} # this is for the atomic ones self.atomic_desc = {} # try to read the xyz file try: if isinstance(self.fxyz, (tuple, list)): self.frames = [] for f in self.fxyz: self.frames += read(f, slice(0, None, self.stride), **self.fileformat) else: self.frames = read(self.fxyz, slice(0, None, self.stride), **self.fileformat) except: raise ValueError('Exception occurred when loading the input file') self.nframes = len(self.frames) all_species = [] for i, frame in enumerate(self.frames): # record the total number of atoms self.natom_list.append(len(frame.get_positions())) all_species.extend(frame.get_atomic_numbers()) if frame.get_pbc()[0] and frame.get_pbc()[1] and frame.get_pbc()[2]: # niggli_reduce niggli_reduce(frame) if not self.periodic or not np.sum(frame.get_cell()) > 0: frame.set_pbc([False, False, False]) # we also initialize the descriptor dictionary for each frame self.global_desc[i] = {} self.atomic_desc[i] = {} self.total_natoms = np.sum(self.natom_list) self.max_atoms = max(self.natom_list) # Keep things in plain python for serialisation self.global_species = np.unique(all_species).tolist() print('load xyz file: ', self.fxyz, ', a total of ', str(self.nframes), 'frames', ', a total of ', str(self.total_natoms), 'atoms', ', with elements: ', self.global_species, '.')
def cross(self, a1, a2): """Crosses the two atoms objects and returns one""" if len(a1) != len(a2): raise ValueError('The two structures do not have the same length') N = len(a1) if self.n_top is None else self.n_top slab = a1[:len(a1) - N] a1 = a1[-N:] a2 = a2[-N:] if not np.array_equal(a1.numbers, a2.numbers): err = 'Trying to pair two structures with different stoichiometry' raise ValueError(err) if self.use_tags and not np.array_equal(a1.get_tags(), a2.get_tags()): err = 'Trying to pair two structures with different tags' raise ValueError(err) a1_copy = a1.copy() a2_copy = a2.copy() if self.cellbounds is not None: if not self.cellbounds.is_within_bounds(a1_copy.get_cell()): niggli_reduce(a1_copy) if not self.cellbounds.is_within_bounds(a2_copy.get_cell()): niggli_reduce(a2_copy) pos1_ref = a1_copy.get_positions() pos2_ref = a2_copy.get_positions() invalid = True counter = 0 maxcount = 1000 # Run until a valid pairing is made or 1000 pairings are tested. while invalid and counter < maxcount: counter += 1 # Choose direction of cutting plane normal (0, 1, or 2): direction = randrange(3) # Randomly translate parent structures: for a, pos in zip([a1_copy, a2_copy], [pos1_ref, pos2_ref]): a.set_positions(pos) cell = a.get_cell() for i in range(3): r = random() cond1 = i == direction and r < self.p1 cond2 = i != direction and r < self.p2 if cond1 or cond2: a.positions += random() * cell[i, :] if self.use_tags: gather_atoms_by_tag(a) else: a.wrap() # Perform the pairing: fraction = random() child = self._get_pairing(a1_copy, a2_copy, direction=direction, fraction=fraction) if child is None: continue # Verify whether the atoms are too close or not: invalid = atoms_too_close(child, self.blmin, use_tags=self.use_tags) if invalid: continue elif self.test_dist_to_slab: invalid = atoms_too_close_two_sets(slab, child, self.blmin) if counter == maxcount: return None return child
from ase.build import niggli_reduce from ase import Atoms from ase.io import write as aseWrite from ioAndInterfaces import ccdcCrystalToASE from ccdc.io import CrystalReader #example input and outputs to test this inputRes, outputRes = 'testingScripts/new.res', 'temp070917.res' myCell = CrystalReader(inputRes)[0] myASECell = ccdcCrystalToASE(myCell) myASECell.set_pbc(True) niggli_reduce(myASECell) aseWrite(outputRes, myASECell) print 'issue with this is that crystal optimiser wants labels etc, and probably fussy with res file format' #could attach labels or something if can be bothered print 'another issue is that the cell may not have the same convention, so would have to reset rather than just changing angles etc'
N = int(sys.argv[1]) # NxNx1 supercell h = 0.15 a = 2.51026699 cell = [[a, 0., 0.], [-a / 2, np.sqrt(3) / 2 * a, 0.], [0., 0., c]] scaled_positions = [[2. / 3, 1. / 3, 0.5], [1. / 3, 2. / 3, 0.5]] system = Atoms('BN', cell=cell, scaled_positions=scaled_positions, pbc=[1, 1, 1]) system = system.repeat((2, 1, 1)) niggli_reduce(system) defect = system.repeat((N, N, 1)) defect[0].symbol = 'C' defect[1].magmom = 1 q = +1 # Defect charge calc = GPAW(mode='fd', kpts={'size': (4, 4, 1)}, xc='PBE', charge=q, occupations=FermiDirac(0.01), txt='BN{0}{0}.CB_charged.txt'.format(N))
def __init__(self, structures=[], info={}, cell_reduce=False, progress=False, suppress_ase_warnings=True): """ Initialize the AtomsCollection | Args: | structures (list[str] or list[ase.Atoms]): list of file names or | Atoms that will form | the collection | info (dict): dictionary of general information to attach | to this collection | cell_reduce (bool): if True, perform a Niggli cell reduction on | all loaded structures | progress (bool): visualize a progress bar for the loading process | suppress_ase_warnings (bool): suppress annoying ASE warnings when | loading files (default is True) """ # Start by parsing out the structures self.structures = [] if isinstance(structures, ase.Atoms): # Well, it's just one... structures = [structures] elif inspect.isgenerator(structures): # Let's unravel it iter_structs = structures structures = [] for s in iter_structs: structures.append(s) if progress: sys.stdout.write("Loading collection...\n") s_n = len(structures) for s_i, struct in enumerate(structures): if progress: # Progress bar sys.stdout.write("\rLoading: {0}".format(utils.progbar(s_i+1, s_n))) # Is it an Atoms object? if type(struct) is ase.Atoms: self.structures.append(ase.Atoms(struct)) # Copy all arrays for k in struct.arrays.keys(): if not self.structures[-1].has(k): self.structures[-1].new_array(k, struct.get_array(k)) if struct.calc is not None: # Prevents pointless attempts at re-calculating self.structures[-1].calc._old_atoms = self.structures[-1] # Or is it a string? elif utils.is_string(struct): with utils.silence_stdio(suppress_ase_warnings, suppress_ase_warnings): self.structures.append(ase_io.read(str(struct))) # If there's no name, give it the filename if 'name' not in self.structures[-1].info: self.structures[-1].info['name'] = utils.seedname(struct) else: raise TypeError('Structures must be Atoms objects or valid ' 'file names,' ' not {0}'.format(type(struct).__name__)) if cell_reduce: # Here we must keep the energy if it was present # We do this by hand because ASE has its good reasons # for severing the atoms-calculator connection when changing # the unit cell. try: _E = self.structures[-1].calc.results['energy'] except (KeyError, AttributeError): _E = None niggli_reduce(self.structures[-1]) if _E is not None: _calc = SinglePointCalculator(self.structures[-1], energy=_E) self.structures[-1].set_calculator(_calc) if progress: sys.stdout.write('\nLoaded {0} structures\n'.format(s_n)) self._all = _AllCaller(self.structures, ase.Atoms) self._arrays = {} # Now assign the info if type(info) is not dict: raise TypeError('Info must be dict,' ' not {0}'.format(type(info).__name__)) else: self.info = info.copy()