def test_fleurinp_modifier_set_kpointsdata(create_fleurinp): """Test if setting a kpoints list to a fleurinp data node works""" from aiida.orm import KpointsData fleurinp_tmp = create_fleurinp(inpxmlfilefolder) fleurinp_tmp.store() # needed? struc = fleurinp_tmp.get_structuredata_ncf() kps = KpointsData() kps.set_cell(struc.cell) kps.pbc = struc.pbc kpoints_pos = [[0.0, 0.0, 0.0], [0.0, 0.5, 0.0], [0.5, 0.0, 0.0], [0.5, 0.0, 0.5], [0.5, 0.5, 0.5], [1.0, 1.0, 1.0]] kpoints_weight = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] # Fleur renormalizes kps.set_kpoints(kpoints_pos, cartesian=False, weights=kpoints_weight) kps.store() # needed, because node has to be loaded... #print(fleurinp_tmp) fm = FleurinpModifier(fleurinp_tmp) fm.set_kpointsdata(kps) fm.show(validate=True, display=False) fm.freeze() # check if kpoint node is input into modification # uuid of node show also work fm = FleurinpModifier(fleurinp_tmp) fm.set_kpointsdata(kps.uuid) fm.freeze()
def _legacy_get_explicit_kpoints_path(structure, **kwargs): """ Call the get_explicit_kpoints_path of the legacy implementation :param structure: a StructureData node :param float kpoint_distance: parameter controlling the distance between kpoints. Distance is given in crystal coordinates, i.e. the distance is computed in the space of b1, b2, b3. The distance set will be the closest possible to this value, compatible with the requirement of putting equispaced points between two special points (since extrema are included). :param bool cartesian: if set to true, reads the coordinates eventually passed in value as cartesian coordinates :param float epsilon_length: threshold on lengths comparison, used to get the bravais lattice info :param float epsilon_angle: threshold on angles comparison, used to get the bravais lattice info """ args_recognized = ['value', 'kpoint_distance', 'cartesian', 'epsilon_length', 'epsilon_angle'] args_unknown = set(kwargs).difference(args_recognized) if args_unknown: raise ValueError('unknown arguments {}'.format(args_unknown)) point_coords, path, bravais_info, explicit_kpoints, labels = legacy.get_explicit_kpoints_path( # pylint: disable=unbalanced-tuple-unpacking cell=structure.cell, pbc=structure.pbc, **kwargs ) kpoints = KpointsData() kpoints.set_cell(structure.cell) kpoints.set_kpoints(explicit_kpoints) kpoints.labels = labels parameters = { 'bravais_info': bravais_info, 'point_coords': point_coords, 'path': path, } return {'parameters': Dict(dict=parameters), 'explicit_kpoints': kpoints}
def get_kpointsdata_ncf(self, name=None, index=None, only_used=False): """ This routine returns an AiiDA :class:`~aiida.orm.KpointsData` type produced from the ``inp.xml`` file. This only works if the kpoints are listed in the in inpxml. This is NOT a calcfunction and does not keep the provenance! :param name: str, optional, if given only the kpoint set with the given name is returned :param index: int, optional, if given only the kpoint set with the given index is returned :returns: :class:`~aiida.orm.KpointsData` node """ from aiida.orm import KpointsData from masci_tools.util.xml.xml_getters import get_kpoints_data # HINT, TODO:? in this routine, the 'cell' you might get in an other way # exp: StructureData.cell, but for this you have to make a structureData Node, # which might take more time for structures with lots of atoms. # then just parsing the cell from the inp.xml # as in the routine get_structureData xmltree, schema_dict = self.load_inpxml() if name is None and index is None: kpoints, weights, cell, pbc = get_kpoints_data(xmltree, schema_dict, only_used=only_used) else: kpoints, weights, cell, pbc = get_kpoints_data(xmltree, schema_dict, name=name, index=index, only_used=only_used) if isinstance(kpoints, dict): kpoints_data = {} for (label, kpoints_set), weights_set in zip(kpoints.items(), weights.values()): kps = KpointsData() kps.set_cell(cell) kps.pbc = pbc kps.set_kpoints(kpoints_set, cartesian=False, weights=weights_set) #kpoints_data.add_link_from(self, label='fleurinp.kpts', link_type=LinkType.CREATE) kps.label = 'fleurinp.kpts' kpoints_data[label] = kps else: kpoints_data = KpointsData() kpoints_data.set_cell(cell) kpoints_data.pbc = pbc kpoints_data.set_kpoints(kpoints, cartesian=False, weights=weights) #kpoints_data.add_link_from(self, label='fleurinp.kpts', link_type=LinkType.CREATE) kpoints_data.label = 'fleurinp.kpts' return kpoints_data
def connect_structure_bands(strct): # pylint: disable=unused-argument alat = 4. cell = np.array([ [alat, 0., 0.], [0., alat, 0.], [0., 0., alat], ]) kpnts = KpointsData() kpnts.set_cell(cell) kpnts.set_kpoints([[0., 0., 0.], [0.1, 0.1, 0.1]]) bands = BandsData() bands.set_kpointsdata(kpnts) bands.set_bands([[1.0, 2.0], [3.0, 4.0]]) return bands
def connect_structure_bands(structure): alat = 4. cell = np.array([ [alat, 0., 0.], [0., alat, 0.], [0., 0., alat], ]) k = KpointsData() k.set_cell(cell) k.set_kpoints([[0., 0., 0.], [0.1, 0.1, 0.1]]) b = BandsData() b.set_kpointsdata(k) b.set_bands([[1.0, 2.0], [3.0, 4.0]]) return b
def change_fleurinp(self): """ create a new fleurinp from the old with certain parameters """ # TODO allow change of kpoint mesh?, tria? wf_dict = self.ctx.wf_dict if self.ctx.scf_needed: try: fleurin = self.ctx.scf.outputs.fleurinp except NotExistent: error = 'Fleurinp generated in the SCF calculation is not found.' self.control_end_wc(error) return self.exit_codes.ERROR_SCF_CALCULATION_FAILED else: if 'fleurinp' not in self.inputs: fleurin = get_fleurinp_from_remote_data(self.inputs.remote) else: fleurin = self.inputs.fleurinp # how can the user say he want to use the given kpoint mesh, ZZ nkpts : False/0 fleurmode = FleurinpModifier(fleurin) fchanges = wf_dict.get('inpxml_changes', []) # apply further user dependend changes if fchanges: try: fleurmode.add_task_list(fchanges) except (ValueError, TypeError) as exc: error = ( 'ERROR: Changing the inp.xml file failed. Tried to apply inpxml_changes' f', which failed with {exc}. I abort, good luck next time!' ) self.control_end_wc(error) return self.exit_codes.ERROR_CHANGING_FLEURINPUT_FAILED kpath = wf_dict['kpath'] explicit = wf_dict['kpoints_explicit'] distance = wf_dict['kpoints_distance'] nkpts = wf_dict['kpoints_number'] listname = wf_dict['klistname'] if explicit is not None: try: fleurmode.set_kpointlist(**explicit) except (ValueError, TypeError) as exc: error = ( 'ERROR: Changing the inp.xml file failed. Tried to apply kpoints_explicit' f', which failed with {exc}. I abort, good luck next time!' ) self.control_end_wc(error) return self.exit_codes.ERROR_CHANGING_FLEURINPUT_FAILED if listname is None: if wf_dict.get('mode') == 'band': listname = 'path-2' if nkpts is None and distance is None: nkpts = 500 if 'kpoints' in self.inputs: fleurmode.set_kpointsdata(self.inputs.kpoints, switch=True) if kpath == 'auto': if fleurin.inp_version >= '0.32' and listname is not None: fleurmode.switch_kpointset(listname) elif isinstance(kpath, dict): if fleurin.inp_version < '0.32': if distance is not None: raise ValueError( 'set_kpath only supports specifying the number of points for the kpoints' ) fleurmode.set_kpath(kpath, nkpts) else: raise ValueError( 'set_kpath is only supported for inputs up to Max4') elif kpath == 'seek': #Use aiida functionality struc = fleurin.get_structuredata() if distance is not None: output = get_explicit_kpoints_path(struc, reference_distance=distance) else: output = get_explicit_kpoints_path(struc) primitive_struc = output['primitive_structure'] #check if primitive_structure and input structure are identical: maxdiff_cell = sum( abs(np.array(primitive_struc.cell) - np.array(struc.cell))).max() if maxdiff_cell > 3e-9: self.report(f'Error in cell : {maxdiff_cell}') self.report( 'WARNING: The structure data from the fleurinp is not the primitive structure type, which is mandatory in some cases' ) output['explicit_kpoints'].store() fleurmode.set_kpointsdata(output['explicit_kpoints'], switch=True) elif kpath == 'skip': return else: #Use ase struc = fleurin.get_structuredata() path = bandpath(kpath, cell=struc.cell, npoints=nkpts, density=distance) special_points = path.special_points labels = [] for label, special_kpoint in special_points.items(): for index, kpoint in enumerate(path.kpts): if sum(abs(np.array(special_kpoint) - np.array(kpoint))).max() < 1e-12: labels.append((index, label)) labels = sorted(labels, key=lambda x: x[0]) kpts = KpointsData() kpts.set_cell(struc.cell) kpts.pbc = struc.pbc weights = np.ones(len(path.kpts)) / len(path.kpts) kpts.set_kpoints(kpoints=path.kpts, cartesian=False, weights=weights, labels=labels) kpts.store() fleurmode.set_kpointsdata(kpts, switch=True) sigma = wf_dict['sigma'] emin = wf_dict['emin'] emax = wf_dict['emax'] if fleurin.inp_version < '0.32': if wf_dict.get('mode') == 'dos': fleurmode.set_inpchanges({'ndir': -1}) if wf_dict.get('mode') == 'dos': change_dict = { 'dos': True, 'minEnergy': emin, 'maxEnergy': emax, 'sigma': sigma } else: change_dict = { 'band': True, 'minEnergy': emin, 'maxEnergy': emax, 'sigma': sigma } fleurmode.set_inpchanges(change_dict) try: fleurmode.show(display=False, validate=True) except etree.DocumentInvalid: error = ( 'ERROR: input, user wanted inp.xml changes did not validate') self.control_end_wc(error) return self.exit_codes.ERROR_INVALID_INPUT_FILE except ValueError as exc: error = ( 'ERROR: input, user wanted inp.xml changes could not be applied.' f'The following error was raised {exc}') self.control_end_wc(error) return self.exit_codes.ERROR_CHANGING_FLEURINPUT_FAILED fleurinp_new = fleurmode.freeze() self.ctx.fleurinp_banddos = fleurinp_new
def get_kpointsdata_ncf(self): """ This routine returns an AiiDA :class:`~aiida.orm.KpointsData` type produced from the ``inp.xml`` file. This only works if the kpoints are listed in the in inpxml. This is NOT a calcfunction and does not keep the provenance! :returns: :class:`~aiida.orm.KpointsData` node """ from aiida.orm import KpointsData # HINT, TODO:? in this routine, the 'cell' you might get in an other way # exp: StructureData.cell, but for this you have to make a structureData Node, # which might take more time for structures with lots of atoms. # then just parsing the cell from the inp.xml # as in the routine get_structureData # Disclaimer: this routine needs some xpath expressions. # these are hardcoded here, therefore maintainance might be needed, # if you want to circumvent this, you have # to get all the paths from somewhere. ####### # all hardcoded xpaths used and attributes names: bravaismatrix_bulk_xpath = '/fleurInput/cell/bulkLattice/bravaisMatrix/' bravaismatrix_film_xpath = '/fleurInput/cell/filmLattice/bravaisMatrix/' kpointlist_xpath = '/fleurInput/calculationSetup/bzIntegration/kPointList/' kpoint_tag = 'kPoint' kpointlist_attrib_posscale = 'posScale' kpointlist_attrib_weightscale = 'weightScale' #kpointlist_attrib_count = 'count' kpoint_attrib_weight = 'weight' row1_tag_name = 'row-1' row2_tag_name = 'row-2' row3_tag_name = 'row-3' ######## if 'inp.xml' not in self.files: print( 'cannot get a KpointsData because fleurinpdata has no inp.xml file yet' ) # TODO what to do in this case? return False # else read in inpxml if self._schema_file_path: # Schema there, parse with schema xmlschema_doc = etree.parse(self._schema_file_path) xmlschema = etree.XMLSchema(xmlschema_doc) parser = etree.XMLParser(attribute_defaults=True, encoding='utf-8') with self.open(path='inp.xml', mode='r') as inpxmlfile: tree = etree.parse(inpxmlfile, parser) tree.xinclude() # remove comments from inp.xml comments = tree.xpath('//comment()') for c in comments: p = c.getparent() p.remove(c) if not xmlschema.validate(tree): raise ValueError( 'Input file is not validated against the schema.') else: # schema not there, parse without print('parsing inp.xml without XMLSchema') with self.open(path='inp.xml', mode='r') as inpxmlfile: tree = etree.parse(inpxmlfile) tree.xinclude() # remove comments from inp.xml comments = tree.xpath('//comment()') for c in comments: p = c.getparent() p.remove(c) root = tree.getroot() # get cell matrix from inp.xml cell = None row1 = root.xpath(bravaismatrix_bulk_xpath + row1_tag_name) # [0].text.split() if row1: # bulk calculation row1 = row1[0].text.split() row2 = root.xpath(bravaismatrix_bulk_xpath + row2_tag_name)[0].text.split() row3 = root.xpath(bravaismatrix_bulk_xpath + row3_tag_name)[0].text.split() # TODO? allow math? for i, cor in enumerate(row1): row1[i] = float(cor) * BOHR_A for i, cor in enumerate(row2): row2[i] = float(cor) * BOHR_A for i, cor in enumerate(row3): row3[i] = float(cor) * BOHR_A cell = [row1, row2, row3] # set boundary conditions pbc1 = [True, True, True] elif root.xpath(bravaismatrix_film_xpath + row1_tag_name): # film calculation row1 = root.xpath(bravaismatrix_film_xpath + row1_tag_name)[0].text.split() row2 = root.xpath(bravaismatrix_film_xpath + row2_tag_name)[0].text.split() row3 = root.xpath(bravaismatrix_film_xpath + row3_tag_name)[0].text.split() for i, cor in enumerate(row1): row1[i] = float(cor) * BOHR_A for i, cor in enumerate(row2): row2[i] = float(cor) * BOHR_A for i, cor in enumerate(row3): row3[i] = float(cor) * BOHR_A # row3 = [0, 0, 0]#? TODO:what has it to be in this case? cell = [row1, row2, row3] pbc1 = [True, True, False] if cell is None: print('Could not extract Bravias matrix out of inp.xml. Is the ' 'Bravias matrix explicitly given? i.e Latnam definition ' 'not supported.') return None # get kpoints only works if kpointlist in inp.xml kpoints = root.xpath(kpointlist_xpath + kpoint_tag) if kpoints: posscale = root.xpath(kpointlist_xpath + '@' + kpointlist_attrib_posscale) weightscale = root.xpath(kpointlist_xpath + '@' + kpointlist_attrib_weightscale) #count = root.xpath(kpointlist_xpath + '@' + kpointlist_attrib_count) kpoints_pos = [] kpoints_weight = [] for kpoint in kpoints: kpoint_pos = kpoint.text.split() for i, kval in enumerate(kpoint_pos): kpoint_pos[i] = float(kval) / float(posscale[0]) kpoint_weight = float( kpoint.get(kpoint_attrib_weight)) / float( weightscale[0]) kpoints_pos.append(kpoint_pos) kpoints_weight.append(kpoint_weight) totalw = 0 for weight in kpoints_weight: totalw = totalw + weight kps = KpointsData() kps.set_cell(cell) kps.pbc = pbc1 kps.set_kpoints(kpoints_pos, cartesian=False, weights=kpoints_weight) #kps.add_link_from(self, label='fleurinp.kpts', link_type=LinkType.CREATE) kps.label = 'fleurinp.kpts' # return {label: kps} return kps else: # TODO parser other kpoints formats, if they fit in an AiiDA node print('No kpoint list in inp.xml') return None