def create_kpoint_descriptor(self, nspins): par = self.parameters bzkpts_kc = kpts2ndarray(par.kpts, self.atoms) kpt_refine = par.experimental.get('kpt_refine') if kpt_refine is None: kd = KPointDescriptor(bzkpts_kc, nspins) self.timer.start('Set symmetry') kd.set_symmetry(self.atoms, self.symmetry, comm=self.world) self.timer.stop('Set symmetry') else: self.timer.start('Set k-point refinement') kd = create_kpoint_descriptor_with_refinement(kpt_refine, bzkpts_kc, nspins, self.atoms, self.symmetry, comm=self.world, timer=self.timer) self.timer.stop('Set k-point refinement') # Update quantities which might have changed, if symmetry # was changed self.symmetry = kd.symmetry self.setups.set_symmetry(kd.symmetry) self.log(kd) return kd
def calculate(self, atoms=None, properties=('energy', ), system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) self.kpts = kpts2ndarray(self.parameters.kpts, atoms) self.write_input(self.atoms, properties, system_changes) if self.command is None: raise RuntimeError('Please set $%s environment variable ' % ('ASE_' + self.name.upper() + '_COMMAND') + 'or supply the command keyword') command = self.command.replace('PREFIX', self.prefix) olddir = os.getcwd() try: print(self.directory) os.chdir(self.directory) print(command) errorcode = subprocess.call(command, shell=True) finally: os.chdir(olddir) if errorcode: raise RuntimeError('%s in %s returned an error: %d' % (self.name, self.directory, errorcode)) self.read_results()
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms) self.kpts = kpts2ndarray(self.parameters.kpts, atoms) icell = atoms.cell.reciprocal() * 2 * np.pi * Bohr n = self.parameters.gridsize offsets = np.indices((n, n, n)).T.reshape((n**3, 1, 3)) - n // 2 eps = 0.5 * (np.dot(self.kpts + offsets, icell)**2).sum(2).T eps.sort() self.eigenvalues = eps[:, :self.parameters.nbands] * Ha self.results = {'energy': 0.0}
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms) self.kpts = kpts2ndarray(self.parameters.kpts, atoms) icell = atoms.get_reciprocal_cell() * 2 * np.pi * Bohr n = 7 offsets = np.indices((n, n, n)).T.reshape((n**3, 1, 3)) - n // 2 eps = 0.5 * (np.dot(self.kpts + offsets, icell)**2).sum(2).T eps.sort() self.eigenvalues = eps[:, :20] * Ha self.results = {'energy': 0.0}
def write_kpoints(self, directory='./', **kwargs): """Writes the KPOINTS file.""" # Don't write anything if KSPACING is being used if self.float_params['kspacing'] is not None: if self.float_params['kspacing'] > 0: return else: raise ValueError("KSPACING value {0} is not allowable. " "Please use None or a positive number." "".format(self.float_params['kspacing'])) p = self.input_params kpoints = open(join(directory, 'KPOINTS'), 'w') kpoints.write('KPOINTS created by Atomic Simulation Environment\n') if isinstance(p['kpts'], dict): p['kpts'] = kpts2ndarray(p['kpts'], atoms=self.atoms) p['reciprocal'] = True shape = np.array(p['kpts']).shape # Wrap scalar in list if necessary if shape == (): p['kpts'] = [p['kpts']] shape = (1, ) if len(shape) == 1: kpoints.write('0\n') if shape == (1, ): kpoints.write('Auto\n') elif p['gamma']: kpoints.write('Gamma\n') else: kpoints.write('Monkhorst-Pack\n') [kpoints.write('%i ' % kpt) for kpt in p['kpts']] kpoints.write('\n0 0 0\n') elif len(shape) == 2: kpoints.write('%i \n' % (len(p['kpts']))) if p['reciprocal']: kpoints.write('Reciprocal\n') else: kpoints.write('Cartesian\n') for n in range(len(p['kpts'])): [kpoints.write('%f ' % kpt) for kpt in p['kpts'][n]] if shape[1] == 4: kpoints.write('\n') elif shape[1] == 3: kpoints.write('1.0 \n') kpoints.close()
def build_kpts_str(atoms, kspacing, kpts, koffset): ''' ''' # KPOINTS - add a MP grid as required if kspacing is not None: kgrid = kspacing_to_grid(atoms, kspacing) elif kpts is not None: if isinstance(kpts, dict) and 'path' not in kpts: kgrid, shift = kpts2sizeandoffsets(atoms=atoms, **kpts) koffset = [] for i, x in enumerate(shift): assert x == 0 or abs(x * kgrid[i] - 0.5) < 1e-14 koffset.append(0 if x == 0 else 1) else: kgrid = kpts else: kgrid = "gamma" # True and False work here and will get converted by ':d' format if isinstance(koffset, int): koffset = (koffset, ) * 3 # BandPath object or bandpath-as-dictionary: if isinstance(kgrid, dict) or hasattr(kgrid, 'kpts'): kpts_str = ['K_POINTS crystal_b\n'] assert hasattr(kgrid, 'path') or 'path' in kgrid kgrid = kpts2ndarray(kgrid, atoms=atoms) kpts_str.append('%s\n' % len(kgrid)) for k in kgrid: kpts_str.append( '{k[0]:.14f} {k[1]:.14f} {k[2]:.14f} 0\n'.format(k=k)) kpts_str.append('\n') elif isinstance(kgrid, str) and (kgrid == "gamma"): kpts_str = ['K_POINTS gamma\n'] kpts_str.append('\n') else: kpts_str = ['K_POINTS automatic\n'] kpts_str.append('{0[0]} {0[1]} {0[2]} {1[0]:d} {1[1]:d} {1[2]:d}\n' ''.format(kgrid, koffset)) kpts_str.append('\n') return kpts_str
def process_special_kwargs(atoms, kwargs): kwargs = kwargs.copy() kpts = kwargs.pop('kpts', None) if kpts is not None: for kw in ['kpoints', 'reducedkpoints', 'kpointsgrid']: if kw in kwargs: raise ValueError('k-points specified multiple times') kptsarray = kpts2ndarray(kpts, atoms) nkpts = len(kptsarray) fullarray = np.empty((nkpts, 4)) fullarray[:, 0] = 1.0 / nkpts # weights fullarray[:, 1:4] = kptsarray kwargs['kpointsreduced'] = fullarray.tolist() # TODO xc=LDA/PBE etc. # The idea is to get rid of the special keywords, since the rest # will be passed to Octopus # XXX do a better check of this for kw in special_ase_keywords: assert kw not in kwargs, kw return kwargs
def process_special_kwargs(atoms, kwargs): kwargs = kwargs.copy() kpts = kwargs.pop('kpts', None) if kpts is not None: for kw in ['kpoints', 'reducedkpoints', 'kpointsgrid']: if kw in kwargs: raise ValueError('k-points specified multiple times') kptsarray = kpts2ndarray(kpts, atoms) nkpts = len(kptsarray) fullarray = np.empty((nkpts, 4)) fullarray[:, 0] = 1.0 / nkpts # weights fullarray[:, 1:4] = kptsarray kwargs['kpointsreduced'] = fullarray.tolist() # TODO xc=LDA/PBE etc. # The idea is to get rid of the special keywords, since the rest # will be passed to Octopus # XXX do a better check of this for kw in Octopus.special_ase_keywords: assert kw not in kwargs return kwargs
def __init__(self, restart=None, ignore_bad_restart_file=FileIOCalculator._deprecated, label='dftb', atoms=None, kpts=None, slako_dir=None, **kwargs): """ All keywords for the dftb_in.hsd input file (see the DFTB+ manual) can be set by ASE. Consider the following input file block: >>> Hamiltonian = DFTB { >>> SCC = Yes >>> SCCTolerance = 1e-8 >>> MaxAngularMomentum = { >>> H = s >>> O = p >>> } >>> } This can be generated by the DFTB+ calculator by using the following settings: >>> calc = Dftb(Hamiltonian_='DFTB', # line is included by default >>> Hamiltonian_SCC='Yes', >>> Hamiltonian_SCCTolerance=1e-8, >>> Hamiltonian_MaxAngularMomentum_='', >>> Hamiltonian_MaxAngularMomentum_H='s', >>> Hamiltonian_MaxAngularMomentum_O='p') In addition to keywords specific to DFTB+, also the following keywords arguments can be used: restart: str Prefix for restart file. May contain a directory. Default is None: don't restart. ignore_bad_restart_file: bool Ignore broken or missing restart file. By default, it is an error if the restart file is missing or broken. label: str (default 'dftb') Prefix used for the main output file (<label>.out). atoms: Atoms object (default None) Optional Atoms object to which the calculator will be attached. When restarting, atoms will get its positions and unit-cell updated from file. kpts: (default None) Brillouin zone sampling: * ``(1,1,1)`` or ``None``: Gamma-point only * ``(n1,n2,n3)``: Monkhorst-Pack grid * ``dict``: Interpreted as a path in the Brillouin zone if it contains the 'path_' keyword. Otherwise it is converted into a Monkhorst-Pack grid using ``ase.calculators.calculator.kpts2sizeandoffsets`` * ``[(k11,k12,k13),(k21,k22,k23),...]``: Explicit (Nkpts x 3) array of k-points in units of the reciprocal lattice vectors (each with equal weight) Additional attribute to be set by the embed() method: pcpot: PointCharge object An external point charge potential (for QM/MM calculations) """ if slako_dir is None: slako_dir = os.environ.get('DFTB_PREFIX', './') if not slako_dir.endswith('/'): slako_dir += '/' self.slako_dir = slako_dir self.default_parameters = dict( Hamiltonian_='DFTB', Hamiltonian_SlaterKosterFiles_='Type2FileNames', Hamiltonian_SlaterKosterFiles_Prefix=self.slako_dir, Hamiltonian_SlaterKosterFiles_Separator='"-"', Hamiltonian_SlaterKosterFiles_Suffix='".skf"', Hamiltonian_MaxAngularMomentum_='', Options_='', Options_WriteResultsTag='Yes') self.pcpot = None self.lines = None self.atoms = None self.atoms_input = None self.do_forces = False self.outfilename = 'dftb.out' FileIOCalculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) # Determine number of spin channels try: entry = kwargs['Hamiltonian_SpinPolarisation'] spinpol = 'colinear' in entry.lower() except KeyError: spinpol = False self.nspin = 2 if spinpol else 1 # kpoint stuff by ase self.kpts = kpts self.kpts_coord = None if self.kpts is not None: initkey = 'Hamiltonian_KPointsAndWeights' mp_mesh = None offsets = None if isinstance(self.kpts, dict): if 'path' in self.kpts: # kpts is path in Brillouin zone self.parameters[initkey + '_'] = 'Klines ' self.kpts_coord = kpts2ndarray(self.kpts, atoms=atoms) else: # kpts is (implicit) definition of # Monkhorst-Pack grid self.parameters[initkey + '_'] = 'SupercellFolding ' mp_mesh, offsets = kpts2sizeandoffsets(atoms=atoms, **self.kpts) elif np.array(self.kpts).ndim == 1: # kpts is Monkhorst-Pack grid self.parameters[initkey + '_'] = 'SupercellFolding ' mp_mesh = self.kpts offsets = [0.] * 3 elif np.array(self.kpts).ndim == 2: # kpts is (N x 3) list/array of k-point coordinates # each will be given equal weight self.parameters[initkey + '_'] = '' self.kpts_coord = np.array(self.kpts) else: raise ValueError('Illegal kpts definition:' + str(self.kpts)) if mp_mesh is not None: eps = 1e-10 for i in range(3): key = initkey + '_empty%03d' % i val = [mp_mesh[i] if j == i else 0 for j in range(3)] self.parameters[key] = ' '.join(map(str, val)) offsets[i] *= mp_mesh[i] assert abs(offsets[i]) < eps or abs(offsets[i] - 0.5) < eps # DFTB+ uses a different offset convention, where # the k-point mesh is already Gamma-centered prior # to the addition of any offsets if mp_mesh[i] % 2 == 0: offsets[i] += 0.5 key = initkey + '_empty%03d' % 3 self.parameters[key] = ' '.join(map(str, offsets)) elif self.kpts_coord is not None: for i, c in enumerate(self.kpts_coord): key = initkey + '_empty%09d' % i c_str = ' '.join(map(str, c)) if 'Klines' in self.parameters[initkey + '_']: c_str = '1 ' + c_str else: c_str += ' 1.0' self.parameters[key] = c_str
def __init__(self, restart=None, ignore_bad_restart_file=False, label='dftb', atoms=None, kpts=None, run_manyDftb_steps=False, **kwargs): """Construct a DFTB+ calculator. run_manyDftb_steps: Logical True: many steps are run by DFTB+, False:a single force&energy calculation at given positions kpts: (int, int, int), dict, or 2D-array If kpts is a tuple (or list) of 3 integers, it is interpreted as the dimensions of a Monkhorst-Pack grid. If kpts is a dict, it will either be interpreted as a path in the Brillouin zone (*) if it contains the 'path' keyword, otherwise it is converted to a Monkhorst-Pack grid (**). (*) see ase.dft.kpoints.bandpath (**) see ase.calculators.calculator.kpts2sizeandoffsets The k-point coordinates can also be provided explicitly, as a (N x 3) array with the scaled coordinates (relative to the reciprocal unit cell vectors). Each of the N k-points will be given equal weight. --------- Additional object (to be set by function embed) pcpot: PointCharge object An external point charge potential (only in qmmm) """ if 'DFTB_PREFIX' in os.environ: self.slako_dir = os.environ['DFTB_PREFIX'].rstrip('/') + '/' else: self.slako_dir = './' # to run Dftb as energy and force calculator use # Driver_MaxSteps=0, if run_manyDftb_steps: # minimisation of molecular dynamics is run by native DFTB+ self.default_parameters = dict( Hamiltonian_='DFTB', Hamiltonian_SlaterKosterFiles_='Type2FileNames', Hamiltonian_SlaterKosterFiles_Prefix=self.slako_dir, Hamiltonian_SlaterKosterFiles_Separator='"-"', Hamiltonian_SlaterKosterFiles_Suffix='".skf"', Hamiltonian_MaxAngularMomentum_='') else: # using ase to get forces and energy only # (single point calculation) self.default_parameters = dict( Hamiltonian_='DFTB', Driver_='ConjugateGradient', Driver_MaxForceComponent='1E-4', Driver_MaxSteps=0, Hamiltonian_SlaterKosterFiles_='Type2FileNames', Hamiltonian_SlaterKosterFiles_Prefix=self.slako_dir, Hamiltonian_SlaterKosterFiles_Separator='"-"', Hamiltonian_SlaterKosterFiles_Suffix='".skf"', Hamiltonian_MaxAngularMomentum_='') self.pcpot = None self.lines = None self.atoms = None self.atoms_input = None self.outfilename = 'dftb.out' FileIOCalculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) # Determine number of spin channels try: entry = kwargs['Hamiltonian_SpinPolarisation'] spinpol = 'colinear' in entry.lower() except KeyError: spinpol = False self.nspin = 2 if spinpol else 1 # kpoint stuff by ase self.kpts = kpts self.kpts_coord = None if self.kpts is not None: initkey = 'Hamiltonian_KPointsAndWeights' mp_mesh = None offsets = None if isinstance(self.kpts, dict): if 'path' in self.kpts: # kpts is path in Brillouin zone self.parameters[initkey + '_'] = 'Klines ' self.kpts_coord = kpts2ndarray(self.kpts, atoms=atoms) else: # kpts is (implicit) definition of # Monkhorst-Pack grid self.parameters[initkey + '_'] = 'SupercellFolding ' mp_mesh, offsets = kpts2sizeandoffsets(atoms=atoms, **self.kpts) elif np.array(self.kpts).ndim == 1: # kpts is Monkhorst-Pack grid self.parameters[initkey + '_'] = 'SupercellFolding ' mp_mesh = self.kpts offsets = [0.] * 3 elif np.array(self.kpts).ndim == 2: # kpts is (N x 3) list/array of k-point coordinates # each will be given equal weight self.parameters[initkey + '_'] = '' self.kpts_coord = np.array(self.kpts) else: raise ValueError('Illegal kpts definition:' + str(self.kpts)) if mp_mesh is not None: eps = 1e-10 for i in range(3): key = initkey + '_empty%03d' % i val = [mp_mesh[i] if j == i else 0 for j in range(3)] self.parameters[key] = ' '.join(map(str, val)) offsets[i] *= mp_mesh[i] assert abs(offsets[i]) < eps or abs(offsets[i] - 0.5) < eps # DFTB+ uses a different offset convention, where # the k-point mesh is already Gamma-centered prior # to the addition of any offsets if mp_mesh[i] % 2 == 0: offsets[i] += 0.5 key = initkey + '_empty%03d' % 3 self.parameters[key] = ' '.join(map(str, offsets)) elif self.kpts_coord is not None: for i, c in enumerate(self.kpts_coord): key = initkey + '_empty%09d' % i c_str = ' '.join(map(str, c)) if 'Klines' in self.parameters[initkey + '_']: c_str = '1 ' + c_str else: c_str += ' 1.0' self.parameters[key] = c_str
# Copyright (c), 2016-2017, Quantum Espresso Foundation and SISSA (Scuola # Internazionale Superiore di Studi Avanzati). All rights reserved. # This file is distributed under the terms of the LGPL-2.1 license. See the # file 'LICENSE' in the root directory of the present distribution, or # https://opensource.org/licenses/LGPL-2.1 # # from ase import Atoms from postqe.ase.io import read_espresso_output if __name__ == "__main__": from ase.calculators.calculator import FileIOCalculator, Calculator, kpts2ndarray Ni = read_espresso_output('Ni.xml') #test= kpts2ndarray({'path': 'GXG', 'npoints': 200},Ni) test = kpts2ndarray([2, 2, 2], Ni) print(test) exit() from postqe.ase.calculator import PostqeCalculator from ase.visualize import view system = 'Ni' test = read_espresso_output(system + '.xml') test.set_calculator(PostqeCalculator(label=system)) print(test.get_atomic_numbers()) print(test.get_cell(True)) print(test.get_positions()) print(test.get_volume()) #view(test) #Ni2.calc.read_results()