def _get_output_nodes(self, output_path, bands_path): """ Extracts output nodes from the standard output and standard error files. (And XML and JSON files) """ from aiida.orm.data.array.trajectory import TrajectoryData import re result_list = [] # Add errors successful = True if output_path is None: errors_list = ['WARNING: No aiida.out file...'] else: successful, errors_list = self.get_errors_from_file(output_path) result_dict = {} result_dict["errors"] = errors_list # Add warnings warnings_list = self.get_warnings_from_file(output_path) result_dict["warnings"] = warnings_list # Add outuput data output_dict = self.get_output_from_file(output_path) result_dict.update(output_dict) # Add parser info dictionary parser_info = {} parser_version = 'aiida-0.11.0--plugin-0.11.5' parser_info['parser_info'] =\ 'AiiDA Vibra Parser V. {}'.format(parser_version) parser_info['parser_warnings'] = [] parsed_dict = dict(result_dict.items() + parser_info.items()) output_data = ParameterData(dict=parsed_dict) link_name = self.get_linkname_outparams() result_list.append((link_name,output_data)) # Parse band-structure information if available if bands_path is not None: bands, coords = self.get_bands(bands_path) from aiida.orm.data.array.bands import BandsData arraybands = BandsData() arraybands.set_kpoints(self._calc.inp.bandskpoints.get_kpoints(cartesian=True)) arraybands.set_bands(bands,units="eV") result_list.append((self.get_linkname_bandsarray(), arraybands)) bandsparameters = ParameterData(dict={"kp_coordinates": coords}) result_list.append((self.get_linkname_bandsparameters(), bandsparameters)) return successful, result_list
def _get_output_nodes(self, output_path, messages_path, xml_path, json_path, bands_path): """ Extracts output nodes from the standard output and standard error files. (And XML and JSON files) """ from aiida.orm.data.array.trajectory import TrajectoryData import re parser_version = 'aiida-0.11.0--plugin-0.11.5' parser_info = {} parser_info['parser_info'] = 'AiiDA Siesta Parser V. {}'.format( parser_version) parser_info['parser_warnings'] = [] result_list = [] if xml_path is None: self.logger.error("Could not find a CML file to parse") # NOTE aiida.xml is not there? raise SiestaOutputParsingError( "Could not find a CML file to parse") # We get everything from the CML file xmldoc = get_parsed_xml_doc(xml_path) if xmldoc is None: self.logger.error("Malformed CML file: cannot parse") raise SiestaCMLParsingError("Malformed CML file: cannot parse") # These are examples of how we can access input items # # Structure (mandatory) # in_struc = self._calc.get_inputs_dict()['structure'] # # Settings (optional) # try: in_settings = self._calc.get_inputs_dict()['settings'] except KeyError: in_settings = None result_dict = get_dict_from_xml_doc(xmldoc) # Add timing information if json_path is None: self.logger.info("Could not find a time.json file to parse") else: from json_time import get_timing_info global_time, timing_decomp = get_timing_info(json_path) if global_time is None: self.logger.info("Cannot fully parse the time.json file") else: result_dict["global_time"] = global_time result_dict["timing_decomposition"] = timing_decomp # Add warnings successful = True if messages_path is None: # Perhaps using an old version of Siesta warnings_list = ['WARNING: No MESSAGES file...'] else: successful, warnings_list = self.get_warnings_from_file( messages_path) result_dict["warnings"] = warnings_list # Add parser info dictionary parsed_dict = dict(result_dict.items() + parser_info.items()) output_data = ParameterData(dict=parsed_dict) link_name = self.get_linkname_outparams() result_list.append((link_name, output_data)) # If the structure has changed, save it if is_variable_geometry(xmldoc): # Get the input structure to copy its site names, # as the CML file traditionally contained only the # atomic symbols. # struc = get_last_structure(xmldoc, in_struc) result_list.append((self.get_linkname_outstructure(), struc)) # Save forces and stress in an ArrayData object forces, stress = get_final_forces_and_stress(xmldoc) if forces is not None and stress is not None: from aiida.orm.data.array import ArrayData arraydata = ArrayData() arraydata.set_array('forces', np.array(forces)) arraydata.set_array('stress', np.array(stress)) result_list.append((self.get_linkname_outarray(), arraydata)) # Parse band-structure information if available if bands_path is not None: bands, coords = self.get_bands(bands_path) from aiida.orm.data.array.bands import BandsData arraybands = BandsData() arraybands.set_kpoints( self._calc.inp.bandskpoints.get_kpoints(cartesian=True)) arraybands.set_bands(bands, units="eV") result_list.append((self.get_linkname_bandsarray(), arraybands)) bandsparameters = ParameterData(dict={"kp_coordinates": coords}) result_list.append( (self.get_linkname_bandsparameters(), bandsparameters)) return successful, result_list
def _aiida_bands_data(self, data, cell, kpoints_dict): if not data: return False kpt_idx = sorted(data.keys()) # list of kpoint indices try: k_list = [kpoints_dict[i] for i in kpt_idx] # list of k-point triplet except KeyError: # kpoint triplets are not present (true for .qp and so on, can not use BandsData) # We use the internal Yambo Format [ [Eo_1, Eo_2,... ], ...[So_1,So_2,] ] # QP_TABLE [[ib_1,ik_1,isp_1] ,[ib_n,ik_n,isp_n]] # Each entry in DATA has corresponding legend in QP_TABLE that defines its details # like ib= Band index, ik= kpoint index, isp= spin polarization index. # Eo_1 => at ib_1, ik_1 isp_1. pdata = ArrayData() QP_TABLE = [] ORD = [] Eo = [] E_minus_Eo = [] So = [] Z = [] for ky in data.keys(): # kp == kpoint index as a string 1,2,.. for ind in range(len(data[ky]['Band'])): try: Eo.append(data[ky]['Eo'][ind]) except KeyError: pass try: E_minus_Eo.append(data[ky]['E-Eo'][ind]) except KeyError: pass try: So.append(data[ky]['Sc|Eo'][ind]) except KeyError: pass try: Z.append(data[ky]['Z'][ind]) except KeyError: pass ik = int(ky) ib = data[ky]['Band'][ind] isp = 0 if 'Spin_Pol' in data[ky].keys(): isp = data[ky]['Spin_Pol'][ind] QP_TABLE.append([ik, ib, isp]) pdata.set_array('Eo', numpy.array(Eo)) pdata.set_array('E_minus_Eo', numpy.array(E_minus_Eo)) pdata.set_array('So', numpy.array(So)) pdata.set_array('Z', numpy.array(Z)) pdata.set_array('qp_table', numpy.array(QP_TABLE)) return pdata quasiparticle_bands = BandsData() quasiparticle_bands.set_cell(cell) quasiparticle_bands.set_kpoints(k_list, cartesian=True) # labels will come from any of the keys in the nested kp_point data, # there is a uniform set of observables for each k-point, ie Band, Eo, ... # ***FIXME BUG does not seem to handle spin polarizes at all when constructing bandsdata*** bands_labels = [ legend for legend in sorted(data[data.keys()[0]].keys()) ] append_list = [[] for i in bands_labels] for kp in kpt_idx: for i in range(len(bands_labels)): append_list[i].append(data[kp][bands_labels[i]]) generalised_bands = [numpy.array(it) for it in append_list] quasiparticle_bands.set_bands(bands=generalised_bands, units='eV', labels=bands_labels) return quasiparticle_bands
def spin_dependent_subparcer(out_info_dict): """ This find the projection and bands arrays from the out_file and out_info_dict. Used to handle the different possible spin-cases in a convenient manner. :param out_info_dict: contains various technical internals useful in parsing :return: ProjectionData, BandsData parsed from out_file """ out_file = out_info_dict["out_file"] spin_down = out_info_dict["spin_down"] od = out_info_dict #using a shorter name for convenience # regular expressions needed for later parsing WaveFraction1_re = re.compile(r"\=(.*?)\*") # state composition 1 WaveFractionremain_re = re.compile(r"\+(.*?)\*") # state comp 2 FunctionId_re = re.compile(r"\#(.*?)\]") # state identity # primes arrays for the later parsing num_wfc = len(od["wfc_lines"]) bands = np.zeros([od["k_states"], od["num_bands"]]) projection_arrays = np.zeros([od["k_states"], od["num_bands"], num_wfc]) try: for i in range(od["k_states"]): if spin_down: i += od["k_states"] # grabs band energy for j in range (i*od["num_bands"],(i+1)*od["num_bands"],1): out_ind = od["e_lines"][j] val = out_file[out_ind].split()[4] bands[i%od["k_states"]][j%od["num_bands"]] = val #subloop grabs pdos wave_fraction = [] wave_id = [] for k in range(od["e_lines"][j]+1,od["psi_lines"][j],1): out_line = out_file[k] wave_fraction += WaveFraction1_re.findall(out_line) wave_fraction += WaveFractionremain_re.findall(out_line) wave_id += FunctionId_re.findall(out_line) if len(wave_id) != len(wave_fraction): raise IndexError for l in range (len(wave_id)): wave_id[l] = int(wave_id[l]) wave_fraction[l] = float(wave_fraction[l]) #sets relevant values in pdos_array projection_arrays[i%od["k_states"]][ j%od["num_bands"]][wave_id[l]-1] = wave_fraction[l] except IndexError: raise QEOutputParsingError("the standard out file does not " "comply with the official " "documentation.") bands_data = BandsData() try: # Attempts to retrive the kpoints from the parent calc parent_calc = out_info_dict["parent_calc"] parent_kpoints = parent_calc.get_inputs_dict()['kpoints'] if len(od['k_vect']) != len(parent_kpoints.get_kpoints()): raise AttributeError bands_data.set_kpointsdata(parent_kpoints) except AttributeError: bands_data.set_kpoints(od['k_vect'].astype(float)) bands_data.set_bands(bands, units='eV') orbitals = out_info_dict["orbitals"] if len(orbitals) != np.shape(projection_arrays[0,0,:])[0]: raise QEOutputParsingError("There was an internal parsing error, " " the projection array shape does not agree" " with the number of orbitals") projection_data = ProjectionData() projection_data.set_reference_bandsdata(bands_data) projections = [projection_arrays[:,:,i] for i in range(len(orbitals))] # Do the bands_check manually here for projection in projections: if np.shape(projection) != np.shape(bands): raise AttributeError("Projections not the same shape as the bands") #insert here some logic to assign pdos to the orbitals pdos_arrays = spin_dependent_pdos_subparcer(out_info_dict) energy_arrays = [out_info_dict["energy"]]*len(orbitals) projection_data.set_projectiondata(orbitals, list_of_projections=projections, list_of_energy=energy_arrays, list_of_pdos=pdos_arrays, bands_check=False) # pdos=pdos_arrays return bands_data, projection_data