def __init__(self, filename="COPL", to_eV=False): # COPL files have an extra trailing blank line with zopen(filename, "rt") as f: contents = f.read().split("\n")[:-1] # The parameters line is the second line in a COPL file. It # contains all parameters that are needed to map the file. parameters = contents[1].split() num_bonds = int(parameters[0]) if int(parameters[1]) == 2: spins = [Spin.up, Spin.down] self.is_spin_polarized = True else: spins = [Spin.up] self.is_spin_polarized = False # The COHP data start in row num_bonds + 3 data = np.array([np.array(row.split(), dtype=float) for row in contents[num_bonds+2:]]).transpose() if to_eV: # LMTO energies have 5 sig figs self.energies = np.array([round_to_sigfigs(energy, 5) for energy in data[0] * Ry_to_eV], dtype=float) self.efermi = round_to_sigfigs(float(parameters[-1])*Ry_to_eV, 5) else: self.energies = data[0] self.efermi = float(parameters[-1]) cohp_data = {} for bond in range(num_bonds): label, length, sites = self._get_bond_data(contents[2+bond]) cohp = {spin: data[2*(bond+s*num_bonds)+1] for s, spin in enumerate(spins)} if to_eV: icohp = {spin: np.array([round_to_sigfigs(i, 5) for i in data[2*(bond+s*num_bonds)+2] * Ry_to_eV]) for s, spin in enumerate(spins)} else: icohp = {spin: data[2*(bond+s*num_bonds)+2] for s, spin in enumerate(spins)} # This takes care of duplicate labels if label in cohp_data: i = 1 lab = "%s-%d" % (label, i) while lab in cohp_data: i += 1 lab = "%s-%d" % (label, i) label = lab cohp_data[label] = {"COHP": cohp, "ICOHP": icohp, "length": length, "sites": sites} self.cohp_data = cohp_data
def test_energies(self): self.assertEqual(self.copl_bise.efermi, -0.17223) self.assertEqual(self.copl_bise_eV.efermi, -2.3433) self.assertEqual(self.copl_fe.efermi, -0.085683) ener_eV = np.array([round_to_sigfigs(energy, 5) for energy in self.copl_bise.energies * Ry_to_eV], dtype=float) self.assertArrayEqual(ener_eV, self.copl_bise_eV.energies) copl_icohp = self.copl_bise.cohp_data["Bi1-Se7"]["ICOHP"][Spin.up] icohp = np.array([round_to_sigfigs(i, 5) for i in copl_icohp * Ry_to_eV], dtype=float) icohp_eV = self.copl_bise_eV.cohp_data["Bi1-Se7"]["ICOHP"][Spin.up] self.assertArrayEqual(icohp, icohp_eV)
def test_energies(self): self.assertEqual(self.copl_bise.efermi, -0.17223) self.assertEqual(self.copl_bise_eV.efermi, -2.3433) self.assertEqual(self.copl_fe.efermi, -0.085683) ener_eV = np.array([ round_to_sigfigs(energy, 5) for energy in self.copl_bise.energies * Ry_to_eV ], dtype=float) self.assertArrayEqual(ener_eV, self.copl_bise_eV.energies) copl_icohp = self.copl_bise.cohp_data["Bi1-Se7"]["ICOHP"][Spin.up] icohp = np.array( [round_to_sigfigs(i, 5) for i in copl_icohp * Ry_to_eV], dtype=float) icohp_eV = self.copl_bise_eV.cohp_data["Bi1-Se7"]["ICOHP"][Spin.up] self.assertArrayEqual(icohp, icohp_eV)
def test_round(self): vals = [ 424.2425, 2.3425356, 0.000042535636653, 0.23, 2.468e6, 0, -1.392156 ] sigfigs = range(1, 6) rounded_vals = [[400.0, 420.0, 424.0, 424.2, 424.24], [2.0, 2.3, 2.34, 2.343, 2.3425], [4e-5, 4.3e-5, 4.25e-5, 4.254e-5, 4.2536e-5], [0.2, 0.23, 0.23, 0.23, 0.23], [2e6, 2.5e6, 2.47e6, 2.468e6, 2.468e6], [0, 0, 0, 0, 0], [-1, -1.4, -1.39, -1.392, -1.3922]] for v, val in enumerate(vals): for s, sig in enumerate(sigfigs): self.assertEqual(round_to_sigfigs(val, sig), rounded_vals[v][s]) with self.assertRaises(ValueError): round_to_sigfigs(3.5, -2) with self.assertRaises(TypeError): round_to_sigfigs(3.5, 3.5)
def test_round(self): vals = [424.2425, 2.3425356, 0.000042535636653, 0.23, 2.468e6, 0, -1.392156] sigfigs = range(1, 6) rounded_vals = [[400.0, 420.0, 424.0, 424.2, 424.24], [2.0, 2.3, 2.34, 2.343, 2.3425], [4e-5, 4.3e-5, 4.25e-5, 4.254e-5, 4.2536e-5], [0.2, 0.23, 0.23, 0.23, 0.23], [2e6, 2.5e6, 2.47e6, 2.468e6, 2.468e6], [0, 0, 0, 0, 0], [-1, -1.4, -1.39, -1.392, -1.3922]] for v, val in enumerate(vals): for s, sig in enumerate(sigfigs): self.assertEqual(round_to_sigfigs(val, sig), rounded_vals[v][s]) with self.assertRaises(ValueError): round_to_sigfigs(3.5, -2) with self.assertRaises(TypeError): round_to_sigfigs(3.5, 3.5)
def from_file(cls, fmt, filename=None, structure_file=None, are_coops=False): """ Creates a CompleteCohp object from an output file of a COHP calculation. Valid formats are either LMTO (for the Stuttgart LMTO-ASA code) or LOBSTER (for the LOBSTER code). Args: cohp_file: Name of the COHP output file. Defaults to COPL for LMTO and COHPCAR.lobster/COOPCAR.lobster for LOBSTER. are_coops: Indicates whether the populations are COOPs or COHPs. Defaults to False for COHPs. fmt: A string for the code that was used to calculate the COHPs so that the output file can be handled correctly. Can take the values "LMTO" or "LOBSTER". structure_file: Name of the file containing the structure. If no file name is given, use CTRL for LMTO and POSCAR for LOBSTER. Returns: A CompleteCohp object. """ fmt = fmt.upper() if fmt == "LMTO": # LMTO COOPs and orbital-resolved COHP cannot be handled yet. are_coops = False orb_res_cohp = None if structure_file is None: structure_file = "CTRL" if filename is None: filename = "COPL" cohp_file = LMTOCopl(filename=filename, to_eV=True) elif fmt == "LOBSTER": if structure_file is None: structure_file = "POSCAR" if filename is None: filename = "COOPCAR.lobster" if are_coops \ else "COHPCAR.lobster" warnings.warn( "The bond labels are currently consistent with ICOHPLIST.lobster/ICOOPLIST.lobster, not with " "COHPCAR.lobster/COOPCAR.lobster. Please be aware!") cohp_file = Cohpcar(filename=filename, are_coops=are_coops) orb_res_cohp = cohp_file.orb_res_cohp else: raise ValueError("Unknown format %s. Valid formats are LMTO " "and LOBSTER." % fmt) structure = Structure.from_file(structure_file) efermi = cohp_file.efermi cohp_data = cohp_file.cohp_data energies = cohp_file.energies # Lobster shifts the energies so that the Fermi energy is at zero. # Shifting should be done by the plotter object though. spins = [Spin.up, Spin.down] if cohp_file.is_spin_polarized \ else [Spin.up] if fmt == "LOBSTER": energies += efermi if orb_res_cohp is not None: # If no total COHPs are present, calculate the total # COHPs from the single-orbital populations. Total COHPs # may not be present when the cohpgenerator keyword is used # in LOBSTER versions 2.2.0 and earlier. # TODO: Test this more extensively for label in orb_res_cohp: if cohp_file.cohp_data[label]["COHP"] is None: # print(label) cohp_data[label]["COHP"] = { sp: np.sum([orb_res_cohp[label][orbs]["COHP"][sp] for orbs in orb_res_cohp[label]], axis=0) for sp in spins} if cohp_file.cohp_data[label]["ICOHP"] is None: cohp_data[label]["ICOHP"] = \ {sp: np.sum([orb_res_cohp[label][orbs]["ICOHP"][sp] for orbs in orb_res_cohp[label]], axis=0) for sp in spins} if fmt == "LMTO": # Calculate the average COHP for the LMTO file to be # consistent with LOBSTER output. avg_data = {"COHP": {}, "ICOHP": {}} for i in avg_data: for spin in spins: rows = np.array([cohp_data[label][i][spin] for label in cohp_data]) avg = np.average(rows, axis=0) # LMTO COHPs have 5 significant figures avg_data[i].update({spin: np.array([round_to_sigfigs(a, 5) for a in avg], dtype=float)}) avg_cohp = Cohp(efermi, energies, avg_data["COHP"], icohp=avg_data["ICOHP"]) else: avg_cohp = Cohp(efermi, energies, cohp_data["average"]["COHP"], icohp=cohp_data["average"]["COHP"], are_coops=are_coops) del cohp_data["average"] cohp_dict = {label: Cohp(efermi, energies, cohp_data[label]["COHP"], icohp=cohp_data[label]["ICOHP"], are_coops=are_coops) for label in cohp_data} bond_dict = {label: {"length": cohp_data[label]["length"], "sites": [structure.sites[site] for site in cohp_data[label]["sites"]]} for label in cohp_data} return CompleteCohp(structure, avg_cohp, cohp_dict, bonds=bond_dict, are_coops=are_coops, orb_res_cohp=orb_res_cohp)
def from_file(cls, fmt, filename=None, structure_file=None, are_coops=False): """ Creates a CompleteCohp object from an output file of a COHP calculation. Valid formats are either LMTO (for the Stuttgart LMTO-ASA code) or LOBSTER (for the LOBSTER code). Args: cohp_file: Name of the COHP output file. Defaults to COPL for LMTO and COHPCAR.lobster/COOPCAR.lobster for LOBSTER. are_coops: Indicates whether the populations are COOPs or COHPs. Defaults to False for COHPs. fmt: A string for the code that was used to calculate the COHPs so that the output file can be handled correctly. Can take the values "LMTO" or "LOBSTER". structure_file: Name of the file containing the structure. If no file name is given, use CTRL for LMTO and POSCAR for LOBSTER. Returns: A CompleteCohp object. """ fmt = fmt.upper() if fmt == "LMTO": # LMTO COOPs and orbital-resolved COHP cannot be handled yet. are_coops = False orb_res_cohp = None if structure_file is None: structure_file = "CTRL" if filename is None: filename = "COPL" cohp_file = LMTOCopl(filename=filename, to_eV=True) elif fmt == "LOBSTER": if structure_file is None: structure_file = "POSCAR" if filename is None: filename = "COOPCAR.lobster" if are_coops \ else "COHPCAR.lobster" cohp_file = Cohpcar(filename=filename, are_coops=are_coops) orb_res_cohp = cohp_file.orb_res_cohp else: raise ValueError("Unknown format %s. Valid formats are LMTO " "and LOBSTER." % fmt) structure = Structure.from_file(structure_file) efermi = cohp_file.efermi cohp_data = cohp_file.cohp_data energies = cohp_file.energies # Lobster shifts the energies so that the Fermi energy is at zero. # Shifting should be done by the plotter object though. spins = [Spin.up, Spin.down] if cohp_file.is_spin_polarized \ else [Spin.up] if fmt == "LOBSTER": energies += efermi if orb_res_cohp is not None: # If no total COHPs are present, calculate the total # COHPs from the single-orbital populations. Total COHPs # may not be present when the cohpgenerator keyword is used # in LOBSTER versions 2.2.0 and earlier. for label in orb_res_cohp: if cohp_file.cohp_data[label]["COHP"] is None: cohp_data[label]["COHP"] = \ {sp: np.sum([orb_res_cohp[label][orbs]["COHP"][sp] for orbs in orb_res_cohp[label]], axis=0) for sp in spins} if cohp_file.cohp_data[label]["ICOHP"] is None: cohp_data[label]["ICOHP"] = \ {sp: np.sum([orb_res_cohp[label][orbs]["ICOHP"][sp] for orbs in orb_res_cohp[label]], axis=0) for sp in spins} if fmt == "LMTO": # Calculate the average COHP for the LMTO file to be # consistent with LOBSTER output. avg_data = {"COHP": {}, "ICOHP": {}} for i in avg_data: for spin in spins: rows = np.array([cohp_data[label][i][spin] for label in cohp_data]) avg = np.average(rows, axis=0) # LMTO COHPs have 5 significant figures avg_data[i].update({spin: np.array([round_to_sigfigs(a, 5) for a in avg], dtype=float)}) avg_cohp = Cohp(efermi, energies, avg_data["COHP"], icohp=avg_data["ICOHP"]) else: avg_cohp = Cohp(efermi, energies, cohp_data["average"]["COHP"], icohp=cohp_data["average"]["COHP"], are_coops=are_coops) del cohp_data["average"] cohp_dict = {label: Cohp(efermi, energies, cohp_data[label]["COHP"], icohp=cohp_data[label]["ICOHP"], are_coops=are_coops) for label in cohp_data} bond_dict = {label: {"length": cohp_data[label]["length"], "sites": [structure.sites[site] for site in cohp_data[label]["sites"]]} for label in cohp_data} return CompleteCohp(structure, avg_cohp, cohp_dict, bonds=bond_dict, are_coops=are_coops, orb_res_cohp=orb_res_cohp)