def parse_dosfiles(dosfolder): """ parse dos files to XyData nodes """ from masci_tools.io.common_functions import interpolate_dos from masci_tools.io.common_functions import get_Ry2eV eVscale = get_Ry2eV() ef, dos, dos_int = interpolate_dos(dosfolder, return_original=True) # convert to eV units dos[:, :, 0] = (dos[:, :, 0] - ef) * eVscale dos[:, :, 1:] = dos[:, :, 1:] / eVscale dos_int[:, :, 0] = (dos_int[:, :, 0] - ef) * eVscale dos_int[:, :, 1:] = dos_int[:, :, 1:] / eVscale # create output nodes dosnode = XyData() dosnode.set_x(dos[:, :, 0], 'E-EF', 'eV') name = ['tot', 's', 'p', 'd', 'f', 'g'] name = name[:len(dos[0, 0, 1:]) - 1] + ['ns'] ylists = [[], [], []] for l in range(len(name)): ylists[0].append(dos[:, :, 1 + l]) ylists[1].append('dos ' + name[l]) ylists[2].append('states/eV') dosnode.set_y(ylists[0], ylists[1], ylists[2]) dosnode.label = 'dos_data' dosnode.description = 'Array data containing uniterpolated DOS (i.e. dos at finite imaginary part of energy). 3D array with (atoms, energy point, l-channel) dimensions.' # now create XyData node for interpolated data dosnode2 = XyData() dosnode2.set_x(dos_int[:, :, 0], 'E-EF', 'eV') ylists = [[], [], []] for l in range(len(name)): ylists[0].append(dos_int[:, :, 1 + l]) ylists[1].append('interpolated dos ' + name[l]) ylists[2].append('states/eV') dosnode2.set_y(ylists[0], ylists[1], ylists[2]) dosnode2.label = 'dos_interpol_data' dosnode2.description = 'Array data containing interpolated DOS (i.e. dos at real axis). 3D array with (atoms, energy point, l-channel) dimensions.' return dosnode, dosnode2
def check_dos(self): """ checks if dos of starting potential is ok """ dos_ok = True self.ctx.dos_check_fail_reason = None if self.ctx.check_dos: # check parser output doscal = self.ctx.doscal try: dos_outdict = doscal.outputs.results_wf.get_dict() if not dos_outdict['successful']: self.report("ERROR: DOS workflow unsuccessful") self.ctx.doscheck_ok = False return self.exit_codes.ERROR_DOSRUN_FAILED if dos_outdict['list_of_errors'] != []: self.report( "ERROR: DOS wf output contains errors: {}".format( dos_outdict['list_of_errors'])) self.ctx.doscheck_ok = False return self.exit_codes.ERROR_DOSRUN_FAILED except: self.ctx.doscheck_ok = False return self.exit_codes.ERROR_DOSRUN_FAILED # needed for checks emin = self.ctx.voro_calc.res.emin # check for negative DOS try: dosdata = doscal.outputs.dos_data natom = len(self.ctx.voro_calc.res.shapes) nspin = dos_outdict['nspin'] ener = dosdata.get_x()[1] # shape= natom*nspin, nept totdos = dosdata.get_y()[0][1] # shape= natom*nspin, nept if len(ener) != nspin * natom: self.report( "ERROR: DOS output shape does not fit nspin, natom information: len(energies)={}, natom={}, nspin={}" .format(len(ener), natom, nspin)) self.ctx.doscheck_ok = False return self.exit_codes.ERROR_DOSRUN_FAILED # deal with snpin==1 or 2 cases and check negtive DOS for iatom in range(natom // nspin): for ispin in range(nspin): x, y = ener[iatom * nspin + ispin], totdos[iatom * nspin + ispin] if nspin == 2 and ispin == 0: y = -y if y.min() < 0: self.report( "INFO: negative DOS value found in (atom, spin)=({},{}) at iteration {}" .format(iatom, ispin, self.ctx.iter)) dos_ok = False self.ctx.dos_check_fail_reason = 'DOS negative' # check starting EMIN dosdata_interpol = doscal.outputs.dos_data_interpol ener = dosdata_interpol.get_x()[1] # shape= natom*nspin, nept totdos = dosdata_interpol.get_y()[0][ 1] # shape= natom*nspin, nept [0] for total DOS Ry2eV = get_Ry2eV() for iatom in range(natom // nspin): for ispin in range(nspin): x, y = ener[iatom * nspin + ispin], totdos[iatom * nspin + ispin] xrel = abs(x - (emin - self.ctx.efermi) * Ry2eV) mask_emin = where(xrel == xrel.min()) ymin = abs(y[mask_emin]) if ymin > self.ctx.threshold_dos_zero: self.report( "INFO: DOS at emin not zero! {}>{}".format( ymin, self.ctx.threshold_dos_zero)) dos_ok = False self.ctx.dos_check_fail_reason = 'EMIN too high' except AttributeError: dos_ok = False # check for position of core states ecore_all = self.ctx.voro_calc.res.core_states_group.get( 'energy_highest_lying_core_state_per_atom') ecore_max = max(ecore_all) self.report("INFO: emin= {} Ry".format(emin)) self.report("INFO: highest core state= {} Ry".format(ecore_max)) if ecore_max is not None: if ecore_max >= emin: error = "ERROR: contour contains core states!!!" self.report(error) dos_ok = False self.ctx.dos_check_fail_reason = 'core state in contour' # TODO maybe some logic to automatically deal with this issue? # for now stop if this case occurs return self.exit_codes.ERROR_CORE_STATES_IN_CONTOUR elif abs(ecore_max - emin) < self.ctx.min_dist_core_states: error = "ERROR: core states too close to energy contour start!!!" self.report(error) dos_ok = False self.ctx.dos_check_fail_reason = 'core state too close' else: self.report('INFO: DOS check successful') #TODO check for semi-core-states #TODO check rest of dos_output node if something seems important to check # finally set the value in context (needed in do_iteration_check) if dos_ok: self.ctx.doscheck_ok = True else: self.ctx.doscheck_ok = False
def check_voronoi(self): """ check voronoi output. return True/False if voronoi output is ok/problematic if output is problematic try to increase some parameters (e.g. cluster radius) and rerun up tp N_rerun_max times initializes with returning True """ #do some checks with the voronoi output (finally sets self.ctx.voro_ok) self.ctx.voro_ok = True # check calculation state (calculation must be completed) if not self.ctx.voro_calc.is_finished_ok: self.report("ERROR: Voronoi calculation not in FINISHED state") self.ctx.voro_ok = False return self.exit_codes.ERROR_VORONOI_FAILED # check if parser returned some error voro_parser_errors = self.ctx.voro_calc.res.parser_errors if voro_parser_errors != []: self.report("ERROR: Voronoi Parser returned Error(s): {}".format( voro_parser_errors)) self.ctx.voro_ok = False return self.exit_codes.ERROR_VORONOI_PARSING_FAILED # check self.ctx.nclsmin condition clsinfo = self.ctx.voro_calc.res.cluster_info_group ncls = clsinfo.pop('number_of_clusters') nclsmin_last_calc = 1000 for icls in range(len(clsinfo['cluster_info_atoms'])): tmp_ncls = clsinfo['cluster_info_atoms'][icls]['sites'] if tmp_ncls < nclsmin_last_calc: nclsmin_last_calc = tmp_ncls self.report("INFO: number of atoms in smallest cluster: {}".format( nclsmin_last_calc)) if self.ctx.nclsmin > nclsmin_last_calc or ncls < 1: self.report( "WARNING: minimal cluster smaller than threshold of {}".format( self.ctx.nclsmin)) self.ctx.voro_ok = False # check radii condition radii = self.ctx.voro_calc.res.radii_atoms_group r_ratio1 = radii[0]['rout_over_dist_nn'] r_ratio2 = radii[0]['rmt0_over_rout'] if r_ratio1 >= 100. or r_ratio2 >= 100.: self.report( "ERROR: radii information inconsistent: Rout/dis_NN={}, RMT0/Rout={}" .format(r_ratio1, r_ratio2)) self.ctx.voro_ok = False return self.exit_codes.ERROR_VORONOI_INVALID_RADII # fix emin/emax # remember: efermi, emin and emax are in internal units (Ry) but delta_e is in eV! eV2Ry = 1. / get_Ry2eV() emin_dos = self.ctx.dos_params_dict['emin'] emin_out = self.ctx.voro_calc.res.emin self.report("INFO: emin dos input: {}, emin voronoi output: {}".format( emin_dos, emin_out)) if emin_out - self.ctx.delta_e * eV2Ry < emin_dos: self.ctx.dos_params_dict[ 'emin'] = emin_out - self.ctx.delta_e * eV2Ry self.report( "INFO: emin ({} Ry) - delta_e ({} Ry) smaller than emin ({} Ry) of dos input. Setting automatically to {} Ry" .format(emin_out, self.ctx.delta_e * eV2Ry, emin_dos, emin_out - self.ctx.delta_e * eV2Ry)) ret = self.ctx.voro_calc.outputs.retrieved if 'potential_overwrite' in self.ctx.voro_calc.inputs: potfile_overwrite = self.ctx.voro_calc.inputs.potential_overwrite with potfile_overwrite.open(potfile_overwrite.filename) as f: potfile_path = f.name else: with ret.open(VoronoiCalculation._OUT_POTENTIAL_voronoi) as f: potfile_path = f.name self.ctx.efermi = get_ef_from_potfile(potfile_path) emax = self.ctx.dos_params_dict['emax'] self.report( "INFO: emax dos input: {}, efermi voronoi output: {}".format( emax, self.ctx.efermi)) if emax < self.ctx.efermi + self.ctx.delta_e * eV2Ry: self.ctx.dos_params_dict[ 'emax'] = self.ctx.efermi + self.ctx.delta_e * eV2Ry self.report( "INFO: self.ctx.efermi ({} Ry) + delta_e ({} Ry) larger than emax ({} Ry). Setting automatically to {} Ry" .format(self.ctx.efermi, self.ctx.delta_e * eV2Ry, emax, self.ctx.efermi + self.ctx.delta_e * eV2Ry)) #TODO implement other checks? self.report("INFO: Voronoi check finished with result: {}".format( self.ctx.voro_ok)) # finally return result of check return self.ctx.voro_ok
def run_voronoi(self): """ run voronoi calculation with parameters from input """ # incerement iteration counter self.ctx.iter += 1 # increase some parameters if self.ctx.iter > 1: # check if cluster size is actually the reason for failure if self.ctx.dos_check_fail_reason not in [ 'EMIN too high', 'core state in contour', 'core state too close' ]: self.ctx.r_cls = self.ctx.r_cls * self.ctx.fac_clsincrease structure = self.inputs.structure self.ctx.formula = structure.get_formula() label = 'voronoi calculation step {}'.format(self.ctx.iter) description = '{} vornoi on {}'.format(self.ctx.description_wf, self.ctx.formula) voronoicode = self.inputs.voronoi # get valid KKR parameters if self.ctx.iter > 1: # take value from last run to continue params = self.ctx.last_params first_iter = False else: # used input or defaults in first iteration first_iter = True if 'calc_parameters' in self.inputs: params = self.inputs.calc_parameters else: kkrparams_default = kkrparams() para_version = self._kkr_default_params[1] for key, val in self._kkr_default_params[0].items(): kkrparams_default.set_value(key, val, silent=True) # create Dict node params = Dict(dict=kkrparams_default.get_dict()) params.label = 'Defaults for KKR parameter node' params.description = 'defaults as defined in kkrparams of version {}'.format( para_version) # set last_params accordingly (used below for provenance tracking) self.ctx.last_params = params self.report("INFO: input params: {}".format(params.get_dict())) # check if RCLUSTZ is set and use setting from wf_parameters instead (calls update_params_wf to keep track of provenance) updated_params = False update_list = [] kkr_para = kkrparams() for key, val in params.get_dict().items(): kkr_para.set_value(key, val, silent=True) set_vals = kkr_para.get_set_values() set_vals = [keyvalpair[0] for keyvalpair in set_vals] default_values = kkrparams.get_KKRcalc_parameter_defaults()[0] if 'RCLUSTZ' in set_vals: rcls_input = params.get_dict()['RCLUSTZ'] # set r_cls by default or from input in first iteration if self.ctx.r_cls < rcls_input and first_iter: self.ctx.r_cls = rcls_input updated_params = True update_list.append('RCLUSTZ') elif self.ctx.r_cls > rcls_input: # change rcls with iterations updated_params = True update_list.append('RCLUSTZ') else: updated_params = True update_list.append('RCLUSTZ') # in case of dos check verify that RMAX, GMAX are set and use setting from wf_parameters otherwise if 'RMAX' in set_vals: update_list.append('RMAX') rmax_input = params.get_dict()['RMAX'] elif self.ctx.check_dos: # add only if doscheck is done updated_params = True update_list.append('RMAX') rmax_input = kkrparams.default_values.get('RMAX') if 'GMAX' in set_vals: update_list.append('GMAX') gmax_input = params.get_dict()['GMAX'] elif self.ctx.check_dos: # add only if doscheck is done updated_params = True update_list.append('GMAX') gmax_input = kkrparams.default_values.get('GMAX') # check if any mandatory keys are not set and set them with the default values if missing in input parameters for key, value in default_values.items(): if key not in update_list and key not in set_vals: self.report("INFO: setting {} to default value {}".format( key, value)) kkr_para.set_value(key, value) # check if Fermi lavel should be set with input value if self.ctx.ef_set is not None: update_list.append('ef_set') # check if emin should be changed: skip_voro = False if self.ctx.iter > 1: if (self.ctx.dos_check_fail_reason == 'EMIN too high' or self.ctx.dos_check_fail_reason == 'core state too close'): # decrease emin by self.ctx.delta_e emin_old = self.ctx.dos_params_dict['emin'] eV2Ry = 1. / get_Ry2eV() emin_new = emin_old - self.ctx.delta_e * eV2Ry self.ctx.dos_params_dict['emin'] = emin_new updated_params = True update_list.append('EMIN') skip_voro = True # store updated nodes (also used via last_params in kkr_scf_wc) if updated_params: # set values that are updated if 'RCLUSTZ' in update_list: kkr_para.set_value('RCLUSTZ', self.ctx.r_cls) self.report("INFO: setting RCLUSTZ to {}".format( self.ctx.r_cls)) if 'EMIN' in update_list: kkr_para.set_value('EMIN', emin_new) self.report("INFO: setting EMIN to {}".format(emin_new)) if 'RMAX' in update_list: kkr_para.set_value('RMAX', rmax_input) self.report( "INFO: setting RMAX to {} (needed for DOS check with KKRcode)" .format(rmax_input)) if 'GMAX' in update_list: kkr_para.set_value('GMAX', gmax_input) self.report( "INFO: setting GMAX to {} (needed for DOS check with KKRcode)" .format(gmax_input)) if 'ef_set' in update_list: kkr_para.set_value('EFSET', self.ctx.ef_set) self.report( "INFO: setting Fermi level of stating potential to {}". format(self.ctx.ef_set)) updatenode = Dict(dict=kkr_para.get_dict()) updatenode.description = 'changed values: {}'.format(update_list) if first_iter: updatenode.label = 'initial params from wf input' # used workfunction for provenance tracking if parameters have been changed params = update_params_wf(self.ctx.last_params, updatenode) self.ctx.last_params = params else: updatenode.label = 'updated params: {}'.format(update_list) # also keep track of last voronoi output if that has been used voro_out = self.ctx.voro_calc.outputs.output_parameters params = update_voro_input(self.ctx.last_params, updatenode, voro_out) self.ctx.last_params = params # run voronoi step if not skip_voro: options = { 'queue_name': self.ctx.queue, 'resources': self.ctx.resources, 'max_wallclock_seconds': self.ctx.max_wallclock_seconds, 'custom_scheduler_commands': self.ctx.custom_scheduler_commands } builder = get_inputs_voronoi(voronoicode, structure, options, label, description, params=params) if 'startpot_overwrite' in self.inputs: builder.potential_overwrite = self.inputs.startpot_overwrite self.report('INFO: run voronoi step {}'.format(self.ctx.iter)) future = self.submit(builder) # return remote_voro (passed to dos calculation as input) return ToContext(voro_calc=future) else: self.report( "INFO: skipping voronoi calculation (do DOS run with different emin only)" )
def parse_kkr_outputfile(out_dict, outfile, outfile_0init, outfile_000, timing_file, potfile_out, nonco_out_file, outfile_2='output.2.txt', skip_readin=False): """ Parser method for the kkr outfile. It returns a dictionary with results """ # scaling factors etc. defined globally Ry2eV = get_Ry2eV() doscalc = False # collection of parsing error messages msg_list = [] try: code_version, compile_options, serial_number = get_version_info( outfile) tmp_dict = {} tmp_dict['code_version'] = code_version tmp_dict['compile_options'] = compile_options tmp_dict['calculation_serial_number'] = serial_number out_dict['code_info_group'] = tmp_dict except: msg = "Error parsing output of KKR: Version Info" msg_list.append(msg) try: nspin = get_nspin(outfile_0init) natom = get_natom(outfile_0init) newsosol = use_newsosol(outfile_0init) out_dict['nspin'] = nspin out_dict['number_of_atoms_in_unit_cell'] = natom out_dict['use_newsosol'] = newsosol except: msg = "Error parsing output of KKR: nspin/natom" msg_list.append(msg) try: result = find_warnings(outfile) tmp_dict = {} tmp_dict['number_of_warnings'] = len(result) tmp_dict['warnings_list'] = result out_dict['warnings_group'] = tmp_dict except: msg = "Error parsing output of KKR: search for warnings" msg_list.append(msg) try: result = extract_timings(timing_file) out_dict['timings_group'] = result out_dict['timings_unit'] = 'seconds' except: msg = "Error parsing output of KKR: timings" msg_list.append(msg) try: emin, tempr, Nepts, Npol, N1, N2, N3 = get_econt_info(outfile_0init) tmp_dict = {} tmp_dict['emin'] = emin tmp_dict['emin_unit'] = 'Rydberg' tmp_dict['number_of_energy_points'] = Nepts tmp_dict['temperature'] = tempr tmp_dict['temperature_unit'] = 'Kelvin' tmp_dict['npol'] = Npol tmp_dict['n1'] = N1 tmp_dict['n2'] = N2 tmp_dict['n3'] = N3 out_dict['energy_contour_group'] = tmp_dict if Npol == 0: doscalc = True except: msg = "Error parsing output of KKR: energy contour" msg_list.append(msg) try: alat, twopioveralat = get_alatinfo(outfile_0init) out_dict['alat_internal'] = alat out_dict['two_pi_over_alat_internal'] = twopioveralat out_dict['alat_internal_unit'] = 'a_Bohr' out_dict['two_pi_over_alat_internal_unit'] = '1/a_Bohr' except: msg = "Error parsing output of KKR: alat, 2*pi/alat" msg_list.append(msg) try: nkmesh, kmesh_ie = get_kmeshinfo(outfile_0init, outfile_000) tmp_dict = {} tmp_dict['number_different_kmeshes'] = nkmesh[0] tmp_dict['number_kpoints_per_kmesh'] = nkmesh[1] tmp_dict['kmesh_energypoint'] = kmesh_ie out_dict['kmesh_group'] = tmp_dict except: msg = "Error parsing output of KKR: kmesh" msg_list.append(msg) try: nsym, nsym_used, desc = get_symmetries(outfile_0init) tmp_dict = {} tmp_dict['number_of_lattice_symmetries'] = nsym tmp_dict['number_of_used_symmetries'] = nsym_used tmp_dict['symmetry_description'] = desc out_dict['symmetries_group'] = tmp_dict except: msg = "Error parsing output of KKR: symmetries" msg_list.append(msg) if not doscalc: # in case of dos calculation no ewald summation is done try: rsum, gsum, info = get_ewald(outfile_0init) tmp_dict = {} tmp_dict['ewald_summation_mode'] = info tmp_dict['rsum_cutoff'] = rsum[0] tmp_dict['rsum_number_of_vectors'] = rsum[1] tmp_dict['rsum_number_of_shells'] = rsum[2] tmp_dict['rsum_cutoff_unit'] = 'a_Bohr' tmp_dict['gsum_cutoff'] = gsum[0] tmp_dict['gsum_number_of_vectors'] = gsum[1] tmp_dict['gsum_number_of_shells'] = gsum[2] tmp_dict['gsum_cutoff_unit'] = '1/a_Bohr' out_dict['ewald_sum_group'] = tmp_dict except: msg = "Error parsing output of KKR: ewald summation for madelung poterntial" msg_list.append(msg) try: bv, recbv = get_lattice_vectors(outfile_0init) out_dict['direct_bravais_matrix'] = bv out_dict['reciprocal_bravais_matrix'] = recbv out_dict['direct_bravais_matrix_unit'] = 'alat' out_dict['reciprocal_bravais_matrix_unit'] = '2*pi / alat' except: msg = "Error parsing output of KKR: lattice vectors (direct/reciprocal)" msg_list.append(msg) # this is skipped for qdos run for example if not skip_readin: try: ncore, emax, lmax, descr_max = get_core_states(potfile_out) tmp_dict = {} tmp_dict['number_of_core_states_per_atom'] = ncore tmp_dict['energy_highest_lying_core_state_per_atom'] = emax tmp_dict[ 'energy_highest_lying_core_state_per_atom_unit'] = 'Rydberg' tmp_dict['descr_highest_lying_core_state_per_atom'] = descr_max out_dict['core_states_group'] = tmp_dict except: msg = "Error parsing output of KKR: core_states" msg_list.append(msg) tmp_dict = { } # used to group convergence info (rms, rms per atom, charge neutrality) # also initialize convegence_group where all info stored for all iterations is kept out_dict['convergence_group'] = tmp_dict try: result, result_atoms_last = get_rms(outfile, outfile_000) tmp_dict['rms'] = result[-1] tmp_dict['rms_all_iterations'] = result tmp_dict['rms_per_atom'] = result_atoms_last tmp_dict['rms_unit'] = 'unitless' out_dict['convergence_group'] = tmp_dict except: msg = "Error parsing output of KKR: rms-error" msg_list.append(msg) try: result = get_neutr(outfile) tmp_dict['charge_neutrality'] = result[-1] out_dict['convergence_group'][ 'charge_neutrality_all_iterations'] = result tmp_dict['charge_neutrality_unit'] = 'electrons' out_dict['convergence_group'] = tmp_dict except: msg = "Error parsing output of KKR: charge neutrality" msg_list.append(msg) tmp_dict = { } # used to group magnetism info (spin and orbital moments) try: result = get_magtot(outfile) if len(result) > 0: tmp_dict['total_spin_moment'] = result[-1] out_dict['convergence_group'][ 'total_spin_moment_all_iterations'] = result tmp_dict['total_spin_moment_unit'] = 'mu_Bohr' out_dict['magnetism_group'] = tmp_dict except: msg = "Error parsing output of KKR: total magnetic moment" msg_list.append(msg) try: if nspin > 1: if not newsosol: #reset automatically to None to turn off reading of nonco angles file nonco_out_file = None result, vec, angles = get_spinmom_per_atom( outfile, natom, nonco_out_file) if len(result) > 0: tmp_dict['spin_moment_per_atom'] = result[-1, :] if newsosol: tmp_dict['spin_moment_vector_per_atom'] = vec[:] tmp_dict['spin_moment_angles_per_atom'] = angles[:] tmp_dict['spin_moment_angles_per_atom_unit'] = 'degree' out_dict['convergence_group'][ 'spin_moment_per_atom_all_iterations'] = result[:, :] tmp_dict['spin_moment_unit'] = 'mu_Bohr' out_dict['magnetism_group'] = tmp_dict except: msg = "Error parsing output of KKR: spin moment per atom" msg_list.append(msg) # add orbital moments to magnetis group in parser output try: if nspin > 1 and newsosol: #TODO orbital moment full vectors # so far the KKR code writes only the component of the orbital moment # parallel to the spin moment, thus vec and angles are returned empty # by construction. This might change in the future #result, vec, angles = get_orbmom(outfile, natom, nonco_angles_orbmom) # so for now return only result= array containing all iterations, all atoms, orbital moment parallel to spin quantization axis result = get_orbmom(outfile, natom) if len(result) > 0: tmp_dict['total_orbital_moment'] = sum(result[-1, :]) tmp_dict['orbital_moment_per_atom'] = result[-1, :] #tmp_dict['orbital_moment_vector_per_atom'] = vec[-1,:] #tmp_dict['orbital_moment_angles_per_atom'] = angles[-1,:] out_dict['convergence_group'][ 'orbital_moment_per_atom_all_iterations'] = result[:, :] tmp_dict['orbital_moment_unit'] = 'mu_Bohr' #tmp_dict['orbital_moment_angles_per_atom_unit'] = 'degree' out_dict['magnetism_group'] = tmp_dict except: msg = "Error parsing output of KKR: orbital moment" msg_list.append(msg) try: result = get_EF(outfile) out_dict['fermi_energy'] = result[-1] out_dict['fermi_energy_units'] = 'Ry' out_dict['convergence_group'][ 'fermi_energy_all_iterations'] = result out_dict['convergence_group'][ 'fermi_energy_all_iterations_units'] = 'Ry' except: msg = "Error parsing output of KKR: EF" msg_list.append(msg) try: result = get_DOS_EF(outfile) out_dict['dos_at_fermi_energy'] = result[-1] out_dict['convergence_group'][ 'dos_at_fermi_energy_all_iterations'] = result except: msg = "Error parsing output of KKR: DOS@EF" msg_list.append(msg) try: result = get_Etot(outfile) out_dict['energy'] = result[-1] * Ry2eV out_dict['energy_unit'] = 'eV' out_dict['total_energy_Ry'] = result[-1] out_dict['total_energy_Ry_unit'] = 'Rydberg' out_dict['convergence_group'][ 'total_energy_Ry_all_iterations'] = result except: msg = "Error parsing output of KKR: total energy" msg_list.append(msg) try: result = get_single_particle_energies(outfile_000) out_dict['single_particle_energies'] = result * Ry2eV out_dict['single_particle_energies_unit'] = 'eV' except: msg = "Error parsing output of KKR: single particle energies" msg_list.append(msg) try: result_WS, result_tot, result_C = get_charges_per_atom(outfile_000) niter = len(out_dict['convergence_group']['rms_all_iterations']) natyp = int(len(result_tot) // niter) out_dict['total_charge_per_atom'] = result_tot[-natyp:] out_dict['charge_core_states_per_atom'] = result_C[-natyp:] # this check deals with the DOS case where output is slightly different if len(result_WS) == len(result_C): out_dict['charge_valence_states_per_atom'] = result_WS[ -natyp:] - result_C[-natyp:] out_dict['total_charge_per_atom_unit'] = 'electron charge' out_dict['charge_core_states_per_atom_unit'] = 'electron charge' out_dict['charge_valence_states_per_atom_unit'] = 'electron charge' except: msg = "Error parsing output of KKR: charges" msg_list.append(msg) try: try: niter, nitermax, converged, nmax_reached, mixinfo = get_scfinfo( outfile_0init, outfile_000, outfile) except IndexError: niter, nitermax, converged, nmax_reached, mixinfo = get_scfinfo( outfile_0init, outfile_2, outfile) out_dict['convergence_group']['number_of_iterations'] = niter out_dict['convergence_group'][ 'number_of_iterations_max'] = nitermax out_dict['convergence_group']['calculation_converged'] = converged out_dict['convergence_group']['nsteps_exhausted'] = nmax_reached out_dict['convergence_group']['imix'] = mixinfo[0] out_dict['convergence_group']['strmix'] = mixinfo[1] out_dict['convergence_group']['qbound'] = mixinfo[2] out_dict['convergence_group']['fcm'] = mixinfo[3] out_dict['convergence_group']['idtbry'] = mixinfo[4] out_dict['convergence_group']['brymix'] = mixinfo[5] except: msg = "Error parsing output of KKR: scfinfo" msg_list.append(msg) #convert numpy arrays to standard python lists out_dict = convert_to_pystd(out_dict) # return output with error messages if there are any if len(msg_list) > 0: return False, msg_list, out_dict else: return True, [], out_dict
def parse_voronoi_output(out_dict, outfile, potfile, atominfo, radii, inputfile): """ Parse output of voronoi calculation and return (success, error_messages_list, out_dict) """ # for collection of error messages: msg_list = [] try: code_version, compile_options, serial_number = get_version_info( outfile) tmp_dict = {} tmp_dict['code_version'] = code_version tmp_dict['compile_options'] = compile_options tmp_dict['calculation_serial_number'] = serial_number out_dict['code_info_group'] = tmp_dict except: msg = "Error parsing output of voronoi: Version Info" msg_list.append(msg) try: emin, e_core_max = check_voronoi_output(potfile, outfile) out_dict['emin'] = emin out_dict['emin_units'] = 'Ry' diff_emin_ef = emin - get_ef_from_potfile(potfile) out_dict['emin_minus_efermi_Ry'] = diff_emin_ef out_dict['emin_minus_efermi'] = diff_emin_ef * get_Ry2eV() out_dict['emin_minus_efermi_Ry_units'] = 'Ry' out_dict['emin_minus_efermi_units'] = 'eV' except: msg = "Error parsing output of voronoi: 'EMIN'" msg_list.append(msg) # parse try: ncore, emax, lmax, descr_max = get_core_states(potfile) tmp_dict = {} tmp_dict['number_of_core_states_per_atom'] = ncore tmp_dict['energy_highest_lying_core_state_per_atom'] = emax tmp_dict['energy_highest_lying_core_state_per_atom_unit'] = 'Rydberg' tmp_dict['descr_highest_lying_core_state_per_atom'] = descr_max out_dict['core_states_group'] = tmp_dict except: msg = "Error parsing output of voronoi: core_states" msg_list.append(msg) try: Ncls, natom, results = get_cls_info(outfile) clsinfo = [] tmpdict_all = {} for icls in range(natom): tmpdict = {} tmpdict['iatom'] = results[icls][0] tmpdict['refpot'] = results[icls][1] tmpdict['rmt_ref'] = results[icls][2] tmpdict['tb_cluster_id'] = results[icls][3] tmpdict['sites'] = results[icls][4] clsinfo.append(tmpdict) tmpdict_all['cluster_info_atoms'] = clsinfo tmpdict_all['number_of_clusters'] = Ncls out_dict['cluster_info_group'] = tmpdict_all except: msg = "Error parsing output of voronoi: Cluster Info" msg_list.append(msg) try: out_dict['start_from_jellium_potentials'] = startpot_jellium(outfile) except: msg = "Error parsing output of voronoi: Jellium startpot" msg_list.append(msg) try: natyp, naez, shapes = get_shape_array(outfile, atominfo) out_dict['shapes'] = shapes except: msg = "Error parsing output of voronoi: SHAPE Info" msg_list.append(msg) try: Vtot, results = get_volumes(outfile) tmp_dict = {} tmp_dict['volume_total'] = Vtot tmpdict_all = [] for icls in range(naez): tmpdict = {} tmpdict['iatom'] = results[icls][0] tmpdict['v_atom'] = results[icls][1] tmpdict_all.append(tmpdict) tmp_dict['volume_atoms'] = tmpdict_all tmp_dict['volume_unit'] = 'alat^3' out_dict['volumes_group'] = tmp_dict except: msg = "Error parsing output of voronoi: Volume Info" msg_list.append(msg) try: results = get_radii(naez, radii) tmpdict_all = [] for icls in range(naez): tmpdict = {} tmpdict['iatom'] = results[icls][0] tmpdict['rmt0'] = results[icls][1] tmpdict['rout'] = results[icls][2] tmpdict['dist_nn'] = results[icls][4] tmpdict['rmt0_over_rout'] = results[icls][3] tmpdict['rout_over_dist_nn'] = results[icls][5] tmpdict_all.append(tmpdict) tmpdict_all.append({'radii_units': 'alat'}) out_dict['radii_atoms_group'] = tmpdict_all except: msg = "Error parsing output of voronoi: radii.dat Info" msg_list.append(msg) try: results = get_fpradius(naez, atominfo) out_dict['fpradius_atoms'] = results out_dict['fpradius_atoms_unit'] = 'alat' except: msg = "Error parsing output of voronoi: full potential radius" msg_list.append(msg) try: result = get_alat(inputfile) out_dict['alat'] = result out_dict['alat_unit'] = 'a_Bohr' except: msg = "Error parsing output of voronoi: alat" msg_list.append(msg) try: result = get_radial_meshpoints(potfile) out_dict['radial_meshpoints'] = result except: msg = "Error parsing output of voronoi: radial meshpoints" msg_list.append(msg) # some consistency checks comparing lists with natyp/naez numbers #TODO implement checks #convert numpy arrays to standard python lists out_dict = convert_to_pystd(out_dict) # return output with error messages if there are any if len(msg_list) > 0: return False, msg_list, out_dict else: return True, [], out_dict
def parse_kkrimp_outputfile(self, out_dict, file_dict): """ Main parser function for kkrimp, read information from files in file_dict and fills out_dict :param out_dict: dictionary that is filled with parsed output of the KKRimp calculation :param file_dict: dictionary of files that are parsed :returns: success (bool), msg_list(list of error/warning messages of parser), out_dict (filled dict of parsed output) :note: file_dict should contain the following keys * 'outfile', the std_out of the KKRimp calculation * 'out_log', the out_log.000.txt file * 'out_pot', the output potential * 'out_enersp_at', the out_energysp_per_atom_eV file * 'out_enertot_at', the out_energytotal_per_atom_eV file * 'out_timing', the timing file * 'kkrflex_llyfac', the file for the Lloyd factor * 'kkrflex_angles', the nonco_angles file for the KKRimp calculation * 'out_spinmoms', the output spin moments file * 'out_orbmoms', the output orbital moments file """ from masci_tools.io.parsers.kkrparser_functions import get_rms, find_warnings, get_charges_per_atom, get_core_states from masci_tools.io.common_functions import get_version_info, get_Ry2eV Ry2eV = get_Ry2eV() msg_list = [] files = file_dict try: code_version, compile_options, serial_number = get_version_info( files['out_log']) tmp_dict = {} tmp_dict['code_version'] = code_version tmp_dict['compile_options'] = compile_options tmp_dict['calculation_serial_number'] = serial_number out_dict['code_info_group'] = tmp_dict except: msg = "Error parsing output of KKRimp: Version Info" msg_list.append(msg) tmp_dict = { } # used to group convergence info (rms, rms per atom, charge neutrality) # also initialize convegence_group where all info stored for all iterations is kept out_dict['convergence_group'] = tmp_dict try: result, result_atoms_last = get_rms(files['outfile'], files['out_log']) tmp_dict['rms'] = result[-1] tmp_dict['rms_all_iterations'] = result tmp_dict['rms_per_atom'] = result_atoms_last tmp_dict['rms_unit'] = 'unitless' out_dict['convergence_group'] = tmp_dict except: msg = "Error parsing output of KKRimp: rms-error" msg_list.append(msg) try: natom = self._get_natom(files['out_log']) nspin = self._get_nspin(files['out_log'], natom) newsosol = self._get_newsosol(files['out_log']) out_dict['nspin'] = nspin out_dict['number_of_atoms_in_unit_cell'] = natom out_dict['use_newsosol'] = newsosol except: msg = "Error parsing output of KKRimp: nspin/natom" msg_list.append(msg) tmp_dict = { } # used to group magnetism info (spin and orbital moments) try: if nspin > 1 and newsosol: spinmom_vec, spinmom_vec_all, magtot = self._get_spinmom_per_atom( files['out_spinmoms'], natom) tmp_dict['total_spin_moment'] = magtot out_dict['convergence_group'][ 'spin_moment_per_atom'] = spinmom_vec out_dict['convergence_group'][ 'spin_moment_per_atom_all_iterations'] = spinmom_vec_all tmp_dict['total_spin_moment_unit'] = 'mu_Bohr' out_dict['magnetism_group'] = tmp_dict elif nspin > 1: spinmom_vec, spinmom_vec_all, magtot = self._get_magtot( files['out_log'], natom) tmp_dict['total_spin_moment'] = magtot out_dict['convergence_group'][ 'spin_moment_per_atom'] = spinmom_vec out_dict['convergence_group'][ 'spin_moment_per_atom_all_iterations'] = spinmom_vec_all tmp_dict['total_spin_moment_unit'] = 'mu_Bohr' out_dict['magnetism_group'] = tmp_dict except: msg = "Error parsing output of KKRimp: spin moment per atom" msg_list.append(msg) # add orbital moments to magnetism group in parser output try: if nspin > 1 and newsosol and files['out_orbmoms'] is not None: orbmom_atom, orbmom_atom_all = self._get_orbmom_per_atom( files['out_orbmoms'], natom) tmp_dict['orbital_moment_per_atom'] = orbmom_atom out_dict['convergence_group'][ 'orbital_moment_per_atom_all_iterations'] = orbmom_atom_all tmp_dict['orbital_moment_unit'] = 'mu_Bohr' out_dict['magnetism_group'] = tmp_dict except: msg = "Error parsing output of KKRimp: orbital moment" msg_list.append(msg) try: result = self._get_EF_potfile(files['out_pot']) out_dict['fermi_energy'] = result out_dict['fermi_energy_units'] = 'Ry' except: msg = "Error parsing output of KKRimp: EF" msg_list.append(msg) try: result = self._get_Etot(files['out_log']) out_dict['energy'] = result[-1] * Ry2eV out_dict['energy_unit'] = 'eV' out_dict['total_energy_Ry'] = result[-1] out_dict['total_energy_Ry_unit'] = 'Rydberg' out_dict['convergence_group'][ 'total_energy_Ry_all_iterations'] = result except: msg = "Error parsing output of KKRimp: total energy" msg_list.append(msg) try: result = find_warnings(files['outfile']) tmp_dict = {} tmp_dict['number_of_warnings'] = len(result) tmp_dict['warnings_list'] = result out_dict['warnings_group'] = tmp_dict except: msg = "Error parsing output of KKRimp: search for warnings" msg_list.append(msg) try: result = self._extract_timings(files['out_timing']) out_dict['timings_group'] = result out_dict['timings_unit'] = 'seconds' except: msg = "Error parsing output of KKRimp: timings" msg_list.append(msg) try: esp_at, etot_at = self._get_energies_atom(files['out_enersp_at'], files['out_enertot_at'], natom) out_dict['single_particle_energies'] = esp_at * Ry2eV out_dict['single_particle_energies_unit'] = 'eV' out_dict['total_energies_atom'] = etot_at * Ry2eV out_dict['total_energies_atom_unit'] = 'eV' except: msg = "Error parsing output of KKRimp: single particle energies" msg_list.append(msg) try: result_WS, result_tot, result_C = get_charges_per_atom( files['out_log']) niter = len(out_dict['convergence_group']['rms_all_iterations']) natyp = int(len(result_tot) / niter) out_dict['total_charge_per_atom'] = result_WS[-natyp:] out_dict['charge_core_states_per_atom'] = result_C[-natyp:] # this check deals with the DOS case where output is slightly different if len(result_WS) == len(result_C): out_dict['charge_valence_states_per_atom'] = result_WS[ -natyp:] - result_C[-natyp:] out_dict['total_charge_per_atom_unit'] = 'electron charge' out_dict['charge_core_states_per_atom_unit'] = 'electron charge' out_dict['charge_valence_states_per_atom_unit'] = 'electron charge' except: msg = "Error parsing output of KKRimp: charges" msg_list.append(msg) try: econt = self._get_econt_info(files['out_log']) tmp_dict = {} tmp_dict['emin'] = econt.get('emin') tmp_dict['emin_unit'] = 'Rydberg' tmp_dict['number_of_energy_points'] = econt.get('Nepts') tmp_dict['epoints_contour'] = econt.get('epts') tmp_dict['epoints_contour_unit'] = 'Rydberg' tmp_dict['epoints_weights'] = econt.get('weights') out_dict['energy_contour_group'] = tmp_dict except: msg = "Error parsing output of KKRimp: energy contour" msg_list.append(msg) try: ncore, emax, lmax, descr_max = get_core_states(files['out_pot']) tmp_dict = {} tmp_dict['number_of_core_states_per_atom'] = ncore tmp_dict['energy_highest_lying_core_state_per_atom'] = emax tmp_dict[ 'energy_highest_lying_core_state_per_atom_unit'] = 'Rydberg' tmp_dict['descr_highest_lying_core_state_per_atom'] = descr_max out_dict['core_states_group'] = tmp_dict except: msg = "Error parsing output of KKRimp: core_states" msg_list.append(msg) try: niter, nitermax, converged, nmax_reached, mixinfo = self._get_scfinfo( files['out_log']) out_dict['convergence_group']['number_of_iterations'] = niter out_dict['convergence_group'][ 'number_of_iterations_max'] = nitermax out_dict['convergence_group']['calculation_converged'] = converged out_dict['convergence_group']['nsteps_exhausted'] = nmax_reached out_dict['convergence_group']['imix'] = mixinfo[0] out_dict['convergence_group']['strmix'] = mixinfo[1] out_dict['convergence_group']['qbound'] = mixinfo[2] out_dict['convergence_group']['fcm'] = mixinfo[3] out_dict['convergence_group']['brymix'] = mixinfo[1] except: msg = "Error parsing output of KKRimp: scfinfo" msg_list.append(msg) #convert arrays to lists from numpy import ndarray for key in list(out_dict.keys()): if type(out_dict[key]) == ndarray: out_dict[key] = list(out_dict[key]) elif type(out_dict[key]) == dict: for subkey in list(out_dict[key].keys()): if type(out_dict[key][subkey]) == ndarray: out_dict[key][subkey] = ( out_dict[key][subkey]).tolist() # return output with error messages if there are any if len(msg_list) > 0: return False, msg_list, out_dict else: return True, [], out_dict
def parse_impdosfiles(dos_abspath, natom, nspin, ef): """ Read `out_ldos*` files and create XyData node with l-resolved DOS (+node for interpolated DOS if files are found) Inputs: :param dos_abspath: absolute path to folder where `out_ldos*` files reside (AiiDA Str object) :param natom: number of atoms (AiiDA Int object) :param nspin: number of spin channels (AiiDA Int object) :param ef: Fermi energy in Ry units (AiiDA Float object) Returns: output dictionary containing output = {'dos_data': dosnode, 'dos_data_interpol': dosnode2} where `dosnode` and `dosnode2` are AiiDA XyData objects """ from masci_tools.io.common_functions import get_Ry2eV, get_ef_from_potfile from numpy import loadtxt, array # add '/' if missing from path abspath = dos_abspath.value if abspath[-1] != '/': abspath += '/' # read dos files dos, dos_int = [], [] for iatom in range(1, natom.value + 1): for ispin in range(1, nspin.value + 1): with open(abspath + 'out_ldos.atom=%0.2i_spin%i.dat' % (iatom, ispin)) as dosfile: tmp = loadtxt(dosfile) dos.append(tmp) with open(abspath + 'out_ldos.interpol.atom=%0.2i_spin%i.dat' % (iatom, ispin)) as dosfile: tmp = loadtxt(dosfile) dos_int.append(tmp) dos, dos_int = array(dos), array(dos_int) # convert to eV units eVscale = get_Ry2eV() dos[:, :, 0] = (dos[:, :, 0] - ef.value) * eVscale dos[:, :, 1:] = dos[:, :, 1:] / eVscale dos_int[:, :, 0] = (dos_int[:, :, 0] - ef.value) * eVscale dos_int[:, :, 1:] = dos_int[:, :, 1:] / eVscale # create output nodes dosnode = XyData() dosnode.label = 'dos_data' dosnode.description = 'Array data containing uniterpolated DOS (i.e. dos at finite imaginary part of energy). 3D array with (atoms, energy point, l-channel) dimensions.' dosnode.set_x(dos[:, :, 0], 'E-EF', 'eV') name = ['tot', 's', 'p', 'd', 'f', 'g'] name = name[:len(dos[0, 0, 1:]) - 1] + ['ns'] ylists = [[], [], []] for l in range(len(name)): ylists[0].append(dos[:, :, 1 + l]) ylists[1].append('dos ' + name[l]) ylists[2].append('states/eV') dosnode.set_y(ylists[0], ylists[1], ylists[2]) # node for interpolated DOS dosnode2 = XyData() dosnode2.label = 'dos_interpol_data' dosnode2.description = 'Array data containing iterpolated DOS (i.e. dos at finite imaginary part of energy). 3D array with (atoms, energy point, l-channel) dimensions.' dosnode2.set_x(dos_int[:, :, 0], 'E-EF', 'eV') ylists = [[], [], []] for l in range(len(name)): ylists[0].append(dos_int[:, :, 1 + l]) ylists[1].append('interpolated dos ' + name[l]) ylists[2].append('states/eV') dosnode2.set_y(ylists[0], ylists[1], ylists[2]) output = {'dos_data': dosnode, 'dos_data_interpol': dosnode2} return output
def set_params_flex(self): """ Take input parameter node and change to input from wf_parameter and options """ self.report('INFO: setting parameters ...') params = self.ctx.input_params_KKR input_dict = params.get_dict() para_check = kkrparams() # step 1: try to fill keywords try: for key, val in input_dict.items(): para_check.set_value(key, val, silent=True) except: return self.exit_codes.ERROR_INVALID_CALC_PARAMETERS # step 2: check if all mandatory keys are there label = '' descr = '' missing_list = para_check.get_missing_keys(use_aiida=True) if missing_list != []: kkrdefaults = kkrparams.get_KKRcalc_parameter_defaults()[0] kkrdefaults_updated = [] for key_default, val_default in list(kkrdefaults.items()): if key_default in missing_list: para_check.set_value(key_default, kkrdefaults.get(key_default), silent=True) kkrdefaults_updated.append(key_default) missing_list.remove(key_default) if len(missing_list) > 0: self.report('ERROR: calc_parameters misses keys: {}'.format( missing_list)) return self.exit_codes.ERROR_CALC_PARAMETERS_INCOMPLETE else: self.report( 'updated KKR parameter node with default values: {}'. format(kkrdefaults_updated)) label = 'add_defaults_' descr = 'added missing default keys, ' # updatedict contains all things that will be updated with update_params_wf later on updatedict = {} runopt = para_check.get_dict().get('RUNOPT', None) if runopt == None: runopt = [] # overwrite some parameters of the KKR calculation by hand before setting mandatory keys if "params_kkr_overwrite" in self.inputs: for key, val in self.inputs.params_kkr_overwrite.get_dict().items( ): if key != runopt: updatedict[key] = val else: runopt = val self.report( 'INFO: overwriting KKR parameter: {} with {} from params_kkr_overwrite input node' .format(key, val)) runopt = [i.strip() for i in runopt] if 'KKRFLEX' not in runopt: runopt.append('KKRFLEX') updatedict['RUNOPT'] = runopt self.report('INFO: RUNOPT set to: {}'.format(runopt)) if 'wf_parameters' in self.inputs: if self.ctx.dos_run: for key, val in { 'EMIN': self.ctx.dos_params_dict['emin'], 'EMAX': self.ctx.dos_params_dict['emax'], 'NPT2': self.ctx.dos_params_dict['nepts'], 'NPOL': 0, 'NPT1': 0, 'NPT3': 0, 'BZDIVIDE': self.ctx.dos_params_dict['kmesh'], 'IEMXD': self.ctx.dos_params_dict['nepts'], 'TEMPR': self.ctx.dos_params_dict['tempr'] }.items(): updatedict[key] = val elif self.ctx.ef_shift != 0: # extract old Fermi energy in Ry remote_data_parent = self.inputs.remote_data parent_calc = remote_data_parent.get_incoming( link_label_filter='remote_folder').first().node ef_old = parent_calc.outputs.output_parameters.get_dict().get( 'fermi_energy') # get Fermi energy shift in eV ef_shift = self.ctx.ef_shift #set new E_F in eV # calculate new Fermi energy in Ry ef_new = (ef_old + ef_shift / get_Ry2eV()) self.report( 'INFO: ef_old + ef_shift = ef_new: {} eV + {} eV = {} eV'. format(ef_old * get_Ry2eV(), ef_shift, ef_new * get_Ry2eV())) updatedict['ef_set'] = ef_new #construct the final param node containing all of the params updatenode = Dict(dict=updatedict) updatenode.label = label + 'KKRparam_flex' updatenode.description = descr + 'KKR parameter node extracted from parent parameters and wf_parameter and options input node.' paranode_flex = update_params_wf(self.ctx.input_params_KKR, updatenode) self.ctx.flex_kkrparams = paranode_flex self.ctx.flex_runopt = runopt self.report('INFO: Updated params= {}'.format( paranode_flex.get_dict()))
def collect_data_and_fit(self): """ collect output of KKR calculations and perform eos fitting to collect results """ self.report('INFO: collect kkr results and fit data') calc_uuids = self.ctx.kkr_calc_uuids etot = [] for iic in range(len(calc_uuids)): uuid = calc_uuids[iic] n = load_node(uuid) try: d_result = n.outputs.output_kkr_scf_wc_ParameterResults.get_dict( ) self.report( 'INFO: extracting output of calculation {}: successful={}, rms={}' .format(uuid, d_result[u'successful'], d_result[u'convergence_value'])) if d_result[u'successful']: pk_last_calc = d_result['last_calc_nodeinfo']['pk'] n2 = load_node(pk_last_calc) scale = self.ctx.scale_factors[iic] ener = n2.outputs.output_parameters.get_dict( )['total_energy_Ry'] rms = d_result[u'convergence_value'] scaled_struc = self.ctx.scaled_structures[iic] v = scaled_struc.get_cell_volume() if rms <= self.ctx.rms_threshold: # only take those calculations which etot.append([scale, ener, v, rms]) else: warn = 'rms of calculation with uuid={} not low enough ({} > {})'.format( uuid, rms, self.ctx.rms_threshold) self.report('WARNING: {}'.format(warn)) self.ctx.warnings.append(warn) except: warn = 'calculation with uuid={} not successful'.format(uuid) self.report('WARNING: {}'.format(warn)) self.ctx.warnings.append(warn) # collect calculation outcome etot = array(etot) self.report('INFO: collected data from calculations= {}'.format(etot)) # check if at least 3 points were successful (otherwise fit does not work) if len(etot) < 3: return self.exit_codes.ERROR_NOT_ENOUGH_SUCCESSFUL_CALCS scalings = etot[:, 0] rms = etot[:, -1] # convert to eV and per atom units etot = etot / len(scaled_struc.sites) # per atom values etot[:, 1] = etot[:, 1] * get_Ry2eV() # convert energy from Ry to eV volumes, energies = etot[:, 2], etot[:, 1] # do multiple fits to data self.report('INFO: output of fits:') self.report('{:18} {:8} {:7} {:7}'.format('fitfunc', 'v0', 'e0', 'B')) self.report('-----------------------------------------') fitnames = self.ctx.fitnames alldat = [] fitdata = {} for fitfunc in fitnames: try: eos = EquationOfState(volumes, energies, eos=fitfunc) v0, e0, B = eos.fit() fitdata[fitfunc] = [v0, e0, B] alldat.append([v0, e0, B]) self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format( fitfunc, v0, e0, B)) except: # capture all errors and mark fit as unsuccessful self.ctx.warnings.append( 'fit unsuccessful for {} function'.format(fitfunc)) if fitfunc == self.ctx.fitfunc_gs_out: self.ctx.successful = False alldat = array(alldat) self.report('-----------------------------------------') self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format( 'mean', mean(alldat[:, 0]), mean(alldat[:, 1]), mean(alldat[:, 2]))) self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format( 'std', std(alldat[:, 0]), std(alldat[:, 1]), std(alldat[:, 2]))) # store results in context self.ctx.volumes = volumes self.ctx.energies = energies self.ctx.scalings = scalings self.ctx.rms = rms self.ctx.fitdata = fitdata self.ctx.fit_mean_values = { '<v0>': mean(alldat[:, 0]), '<e0>': mean(alldat[:, 1]), '<B>': mean(alldat[:, 2]) } self.ctx.fit_std_values = { 's_v0': std(alldat[:, 0]), 's_e0': std(alldat[:, 1]), 's_B': std(alldat[:, 2]) }