def test_get_kpoints(self): """Test the `get_kpoints` method.""" kpt = KpointsData() kpt.set_cell_from_structure(self.structure) kpoints = [ [0., 0., 0.], [0.5, 0.5, 0.5], ] cartesian_kpoints = [ [0., 0., 0.], [np.pi / self.alat, np.pi / self.alat, np.pi / self.alat], ] kpt.set_kpoints(kpoints) self.assertEqual( np.abs(kpt.get_kpoints() - np.array(kpoints)).sum(), 0.) self.assertEqual( np.abs( kpt.get_kpoints(cartesian=True) - np.array(cartesian_kpoints)).sum(), 0.) # Check also after storing kpt.store() kpt2 = load_node(kpt.pk) self.assertEqual( np.abs(kpt2.get_kpoints() - np.array(kpoints)).sum(), 0.) self.assertEqual( np.abs( kpt2.get_kpoints(cartesian=True) - np.array(cartesian_kpoints)).sum(), 0.)
def create_kpoints_from_distance(structure, distance, force_parity): """Generate a uniformly spaced kpoint mesh for a given structure. The spacing between kpoints in reciprocal space is guaranteed to be at least the defined distance. :param structure: the StructureData to which the mesh should apply :param distance: a Float with the desired distance between kpoints in reciprocal space :param force_parity: a Bool to specify whether the generated mesh should maintain parity :returns: a KpointsData with the generated mesh """ from numpy import linalg from aiida.orm import KpointsData epsilon = 1E-5 kpoints = KpointsData() kpoints.set_cell_from_structure(structure) kpoints.set_kpoints_mesh_from_density(distance.value, force_parity=force_parity.value) lengths_vector = [linalg.norm(vector) for vector in structure.cell] lengths_kpoint = kpoints.get_kpoints_mesh()[0] is_symmetric_cell = all(abs(length - lengths_vector[0]) < epsilon for length in lengths_vector) is_symmetric_mesh = all(length == lengths_kpoint[0] for length in lengths_kpoint) # If the vectors of the cell all have the same length, the kpoint mesh should be isotropic as well if is_symmetric_cell and not is_symmetric_mesh: nkpoints = max(lengths_kpoint) kpoints.set_kpoints_mesh([nkpoints, nkpoints, nkpoints]) return kpoints
def example_dft(code, pseudo_family): """Run simple silicon DFT calculation.""" print('Testing Abinit Total energy on Silicon using AbinitCalculation') thisdir = os.path.dirname(os.path.realpath(__file__)) structure = StructureData(pymatgen=mg.core.Structure.from_file( os.path.join(thisdir, 'files', 'Si.cif'))) pseudo_family = Group.objects.get(label=pseudo_family) pseudos = pseudo_family.get_pseudos(structure=structure) kpoints = KpointsData() kpoints.set_cell_from_structure(structure) kpoints.set_kpoints_mesh([2, 2, 2]) # kpoints.set_kpoints_mesh_from_density(2.0) parameters_dict = { 'code': code, 'structure': structure, 'pseudos': pseudos, 'kpoints': kpoints, 'parameters': Dict( dict={ 'ecut': 8.0, # Maximal kinetic energy cut-off, in Hartree 'nshiftk': 4, # of the reciprocal space (that form a BCC lattice !) 'shiftk': [[0.5, 0.5, 0.5], [0.5, 0.0, 0.0], [0.0, 0.5, 0.0], [0.0, 0.0, 0.5]], 'nstep': 20, # Maximal number of SCF cycles 'toldfe': 1.0e-6, # Will stop when, twice in a row, the difference # between two consecutive evaluations of total energy # differ by less than toldfe (in Hartree) }), 'metadata': { 'options': { 'withmpi': True, 'max_wallclock_seconds': 2 * 60, 'resources': { 'num_machines': 1, 'num_mpiprocs_per_machine': 4, } } } } print('Running calculation...') run(AbinitCalculation, **parameters_dict)
def get_distance_from_kmesh(calc): mesh = calc.inputs.kpoints.get_kpoints_mesh()[0] k = KpointsData() k.set_cell_from_structure( calc.inputs.structure ) #these take trace of PBC...if set in the inputs.!! for i in range(4, 400): k.set_kpoints_mesh_from_density(1 / (i * 0.25)) if k.get_kpoints_mesh()[0] == mesh: print('ok, {} is the density'.format(i * 0.25)) print(k.get_kpoints_mesh()[0], mesh) return i * 0.25
def setup_kpoints(self): """ Define the k-point mesh for the relax and scf calculations. """ kpoints_mesh = KpointsData() kpoints_mesh.set_cell_from_structure( self.ctx.structure_initial_primitive) kpoints_mesh.set_kpoints_mesh_from_density( distance=self.ctx.protocol['kpoints_mesh_density'], offset=self.ctx.protocol['kpoints_mesh_offset']) self.ctx.kpoints_mesh = kpoints_mesh
def test_reciprocal_cell(self): """ Test the `reciprocal_cell` method. This is a regression test for #2749. """ kpt = KpointsData() kpt.set_cell_from_structure(self.structure) self.assertEqual(np.abs(kpt.reciprocal_cell - self.expected_reciprocal_cell).sum(), 0.) # Check also after storing kpt.store() kpt2 = load_node(kpt.pk) self.assertEqual(np.abs(kpt2.reciprocal_cell - self.expected_reciprocal_cell).sum(), 0.)
def _get_kpoints(self, key, structure): from aiida.orm import KpointsData if "kpoints" in self._protocols[key]: kpoints_mesh = KpointsData() kpoints_mesh.set_cell_from_structure(structure) kp_dict = self._protocols[key]["kpoints"] if "offset" in kp_dict: kpoints_mesh.set_kpoints_mesh_from_density( distance=kp_dict["distance"], offset=kp_dict["offset"]) else: kpoints_mesh.set_kpoints_mesh_from_density( distance=kp_dict["distance"]) else: kpoints_mesh = None return kpoints_mesh
def run_scf_and_ldos(self): """ Run the SiestaBaseWorkChain in scf+ldos mode on the primitive cell of the relaxed input structure """ try: structure = self.ctx.workchain_relax.outputs.output_structure except: return self.exit_codes.ERROR_RELAXED_STRUCTURE_NOT_AVAILABLE # Do we need further refinement by Seekpath on this=? (eventually)? self.ctx.structure_relaxed_primitive = structure inputs = dict(self.ctx.inputs) ldos_e = "\n {e1} {e2} eV \n %endblock local-density-of-states".format( e1=self.inputs.e1.value, e2=self.inputs.e2.value) inputs['parameters']['%block local-density-of-states'] = ldos_e kpoints_mesh = KpointsData() kpoints_mesh.set_cell_from_structure( self.ctx.structure_relaxed_primitive) kpoints_mesh.set_kpoints_mesh_from_density( distance=self.ctx.protocol['kpoints_mesh_density'], offset=self.ctx.protocol['kpoints_mesh_offset']) # Final input preparation, wrapping dictionaries in ParameterData nodes inputs['kpoints'] = kpoints_mesh inputs['structure'] = self.ctx.structure_relaxed_primitive inputs['parameters'] = Dict(dict=inputs['parameters']) inputs['basis'] = Dict(dict=inputs['basis']) inputs['settings'] = Dict(dict=inputs['settings']) inputs['options'] = Dict(dict=inputs['options']) running = self.submit(SiestaBaseWorkChain, **inputs) self.report('launched SiestaBaseWorkChain<{}> in scf+ldos mode'.format( running.pk)) return ToContext(workchain_base_ldos=running)
def _get_kpoints(self, key, structure, previous_workchain): from aiida.orm import KpointsData if previous_workchain: kpoints_mesh = KpointsData() kpoints_mesh.set_cell_from_structure(structure) previous_wc_kp = previous_workchain.inputs.kpoints kpoints_mesh.set_kpoints_mesh( previous_wc_kp.get_attribute('mesh'), previous_wc_kp.get_attribute('offset')) return kpoints_mesh if 'kpoints' in self._protocols[key]: kpoints_mesh = KpointsData() kpoints_mesh.set_cell_from_structure(structure) kp_dict = self._protocols[key]['kpoints'] if 'offset' in kp_dict: kpoints_mesh.set_kpoints_mesh_from_density( distance=kp_dict['distance'], offset=kp_dict['offset']) else: kpoints_mesh.set_kpoints_mesh_from_density( distance=kp_dict['distance']) return kpoints_mesh return None
def get_explicit_kpoints_path(structure, parameters): """ Return the kpoint path for band structure (in scaled and absolute coordinates), given a crystal structure, using the paths proposed in the various publications (see description of the 'recipe' input parameter). The parameters are the same as get get_explicit_k_path in __init__, but here all structures are input and returned as AiiDA structures rather than tuples, and similarly k-points-related information as a AiiDA KpointsData class. :param structure: The AiiDA StructureData for which we want to obtain the suggested path. :param parameters: A dictionary whose key-value pairs are passed as additional kwargs to the ``seekpath.get_explicit_k_path`` function. :return: A dictionary with four nodes: - ``explicit_kpoints``: a KpointsData with the (explicit) kpoints (with labels set). - ``parameters``: a Dict, whose content is the same dictionary as returned by the ``seekpath.get_explicit_k_path`` function (see `seekpath documentation <https://seekpath.readthedocs.io/>`_), except that: - ``conv_lattice``, ``conv_positions``, ``conv_types`` are removed and replaced by the ``conv_structure`` output node - ``primitive_lattice``, ``primitive_positions``, ``primitive_types`` are removed and replaced by the `primitive_structure` output node - ``reciprocal_primitive_lattice``, ``explicit_kpoints_abs``, ``explicit_kpoints_rel`` and ``explicit_kpoints_labels`` are removed and replaced by the ``explicit_kpoints`` output node - ``primitive_structure``: A StructureData with the primitive structure - ``conv_structure``: A StructureData with the primitive structure """ # pylint: disable=too-many-locals from aiida.tools.data.structure import spglib_tuple_to_structure, structure_to_spglib_tuple structure_tuple, kind_info, kinds = structure_to_spglib_tuple(structure) result = {} rawdict = seekpath.get_explicit_k_path(structure=structure_tuple, **parameters) # Replace primitive structure with AiiDA StructureData primitive_lattice = rawdict.pop('primitive_lattice') primitive_positions = rawdict.pop('primitive_positions') primitive_types = rawdict.pop('primitive_types') primitive_tuple = (primitive_lattice, primitive_positions, primitive_types) primitive_structure = spglib_tuple_to_structure(primitive_tuple, kind_info, kinds) # Replace conv structure with AiiDA StructureData conv_lattice = rawdict.pop('conv_lattice') conv_positions = rawdict.pop('conv_positions') conv_types = rawdict.pop('conv_types') conv_tuple = (conv_lattice, conv_positions, conv_types) conv_structure = spglib_tuple_to_structure(conv_tuple, kind_info, kinds) # Remove reciprocal_primitive_lattice, recalculated by kpoints class rawdict.pop('reciprocal_primitive_lattice') kpoints_abs = rawdict.pop('explicit_kpoints_abs') kpoints_labels = rawdict.pop('explicit_kpoints_labels') # set_kpoints expects labels like [[0,'X'],[34,'L'],...], so generate it here skipping empty labels labels = [[idx, label] for idx, label in enumerate(kpoints_labels) if label] kpoints = KpointsData() kpoints.set_cell_from_structure(primitive_structure) kpoints.set_kpoints(kpoints_abs, cartesian=True, labels=labels) result['parameters'] = Dict(dict=rawdict) result['explicit_kpoints'] = kpoints result['primitive_structure'] = primitive_structure result['conv_structure'] = conv_structure return result
def run_bands(self): """ Run the SiestaBaseWorkChain in scf+bands mode on the primitive cell of the relaxed input structure """ try: structure = self.ctx.workchain_relax.outputs.output_structure except: return self.exit_codes.ERROR_RELAXED_STRUCTURE_NOT_AVAILABLE # Do we need further refinement by Seekpath on this=? (eventually)? self.ctx.structure_relaxed_primitive = structure inputs = dict(self.ctx.inputs) kpoints_mesh = KpointsData() kpoints_mesh.set_cell_from_structure( self.ctx.structure_relaxed_primitive) kpoints_mesh.set_kpoints_mesh_from_density( distance=self.ctx.protocol['kpoints_mesh_density'], offset=self.ctx.protocol['kpoints_mesh_offset']) # For the band-structure kath, it is advised to use the # 'seekpath' method, but we try the 'legacy' for now. In some # cases we might not want seekpath to change our structure. # Further support for this in the input to the workflow might # be needed. (NOTE: If we ever optimize this workflow to # re-use the DM or H resulting from the execution of the Base # workflow, a change in structure would cause errors.) from aiida.tools import get_explicit_kpoints_path legacy_kpath_parameters = Dict( dict={ 'kpoint_distance': 0.05 # In units of b1, b2, b3 (Around 20 points per side...) }) seekpath_kpath_parameters = Dict(dict={ 'reference_distance': 0.02, 'symprec': 0.0001 }) kpath_parameters = legacy_kpath_parameters result = get_explicit_kpoints_path( self.ctx.structure_relaxed_primitive, method='legacy', **kpath_parameters.get_dict()) bandskpoints = result['explicit_kpoints'] # The 'legacy' method presumably does not change the structure ## structure = result['primitive_structure'] self.ctx.kpoints_path = bandskpoints # Final input preparation, wrapping dictionaries in ParameterData nodes inputs['bandskpoints'] = self.ctx.kpoints_path inputs['kpoints'] = kpoints_mesh inputs['structure'] = self.ctx.structure_relaxed_primitive inputs['parameters'] = Dict(dict=inputs['parameters']) inputs['basis'] = Dict(dict=inputs['basis']) inputs['settings'] = Dict(dict=inputs['settings']) running = self.submit(SiestaBaseWorkChain, **inputs) self.report( 'launched SiestaBaseWorkChain<{}> in scf+bands mode'.format( running.pk)) return ToContext(workchain_base_bands=running)
def band_parser_legacy(band_dat, band_kpt, special_points, structure): # pylint: disable=too-many-locals """ Parsers the bands output data, along with the special points retrieved from the input kpoints to construct a BandsData object which is then returned. Cannot handle discontinuities in the kpath, if two points are assigned to same spot only one will be passed. Used for wannier90 < 3.0 :param band_dat: list of str with each str stores one line of aiida_band.dat file :param band_kpt: list of str with each str stores one line of aiida_band.kpt file :param special_points: special points to add labels to the bands a dictionary in the form expected in the input as described in the wannier90 documentation :return: BandsData object constructed from the input params, and a list contains warnings. """ import numpy as np from aiida.orm import BandsData from aiida.orm import KpointsData warnings = [] warnings.append(( "Note: no file named SEEDNAME_band.labelinfo.dat found. " "You are probably using a version of Wannier90 before 3.0. " "There, the labels associated with each k-points were not printed in output " "and there were also cases in which points were not calculated " "(see issue #195 on the Wannier90 GitHub page). " "I will anyway try to do my best to assign labels, " "but the assignment might be wrong " "(especially if there are path discontinuities).")) # imports the data out_kpt = np.genfromtxt(band_kpt, skip_header=1, usecols=(0, 1, 2)) out_dat = np.genfromtxt(band_dat, usecols=1) # reshaps the output bands out_dat = out_dat.reshape(len(out_kpt), (len(out_dat) // len(out_kpt)), order="F") # finds expected points of discontinuity kpath = special_points['path'] cont_break = [(i, (kpath[i - 1][1], kpath[i][0])) for i in range(1, len(kpath)) if kpath[i - 1][1] != kpath[i][0]] # finds the special points special_points_dict = special_points['point_coords'] # We set atol to 1e-5 because in the kpt file the coords are printed with fixed precision labels = [ (i, k) for k in special_points_dict for i in range(len(out_kpt)) if all( np.isclose(special_points_dict[k], out_kpt[i], rtol=0, atol=1.e-5)) ] labels.sort() # Checks and appends labels if discontinuity appends = [] for x in cont_break: # two cases the break is before or the break is after # if the break is before if labels[x[0]][1] != x[1][0]: # checks to see if the discontinuity was already there if labels[x[0] - 1] == x[1][0]: continue insert_point = x[0] new_label = x[1][0] kpoint = labels[x[0]][0] - 1 appends += [[insert_point, new_label, kpoint]] # if the break is after if labels[x[0]][1] != x[1][1]: # checks to see if the discontinuity was already there if labels[x[0] + 1] == x[1][1]: continue insert_point = x[0] + 1 new_label = x[1][1] kpoint = labels[x[0]][0] + 1 appends += [[insert_point, new_label, kpoint]] appends.sort() for i, append in enumerate(appends): labels.insert(append[0] + i, (append[2], six.text_type(append[1]))) bands = BandsData() k = KpointsData() k.set_cell_from_structure(structure) k.set_kpoints(out_kpt, cartesian=False) bands.set_kpointsdata(k) bands.set_bands(out_dat, units='eV') bands.labels = labels return bands, warnings
def band_parser(band_dat, band_kpt, band_labelinfo, structure): # pylint: disable=too-many-locals """ Parsers the bands output data to construct a BandsData object which is then returned. Used for wannier90 >= 3.0 :param band_dat: list of str with each str stores one line of aiida_band.dat file :param band_kpt: list of str with each str stores one line of aiida_band.kpt file :param band_labelinfo: list of str with each str stores one line in aiida_band.labelinfo.dat file :return: BandsData object constructed from the input params """ import numpy as np from aiida.orm import BandsData from aiida.orm import KpointsData warnings = [] # imports the data out_kpt = np.genfromtxt(band_kpt, skip_header=1, usecols=(0, 1, 2)) out_dat = np.genfromtxt(band_dat, usecols=1) # reshaps the output bands out_dat = out_dat.reshape(len(out_kpt), (len(out_dat) // len(out_kpt)), order="F") labels_dict = {} for line_idx, line in enumerate(band_labelinfo, start=1): if not line.strip(): continue try: # label, idx, xval, kx, ky, kz = line.split() label, idx, _, _, _, _ = line.split() except ValueError: warnings.append( ('Wrong number of items in line {} of the labelinfo file - ' 'I will not assign that label')).format(line_idx) continue try: idx = int(idx) except ValueError: warnings.append(( "Invalid value for the index in line {} of the labelinfo file, " "it's not an integer - I will not assign that label" )).format(line_idx) continue # I use a dictionary because there are cases in which there are # two lines for the same point (e.g. when I do a zero-length path, # from a point to the same point, just to have that value) # Note the -1 because in fortran indices are 1-based, in Python are # 0-based labels_dict[idx - 1] = label labels = [(key, labels_dict[key]) for key in sorted(labels_dict)] bands = BandsData() k = KpointsData() k.set_cell_from_structure(structure) k.set_kpoints(out_kpt, cartesian=False) bands.set_kpointsdata(k) bands.set_bands(out_dat, units='eV') bands.labels = labels return bands, warnings