def Ewald_energy(structure_in, core_charges, verbose=True): #-# from copy import deepcopy from pymatgen import Lattice, Structure from pymatgen.analysis import ewald structure = deepcopy(structure_in) lattice = Lattice(structure.get_cell()) coords = structure.get_scaled_positions() structure.charges = [ core_charges[x] for x in structure.get_chemical_symbols() ] struct = Structure(lattice, structure.get_chemical_symbols(), coords, site_properties={"charge": structure.charges}) Ew = ewald.EwaldSummation(struct, compute_forces=True) #Ew= ewald.EwaldSummation(struct, eta=0.057887, acc_factor= 12,compute_forces=True) if verbose: print("=" * 50) print("Real space energy:", Ew.real_space_energy, "[eV]") print("Reciprocal space energy:", Ew.reciprocal_space_energy + Ew.point_energy, "[eV]") print("=" * 50) print("Total electrostatic energy:", Ew.total_energy, "[eV]") return Ew
def ewald_matrix_features(data, noa, data_type="train", file_name_type=""): # noa - number of atoms in unit cell logger.info( "Extracting Ewald matrix features. data_type {0}".format(data_type)) logger.info("data.shape: " + str(data.shape)) ids, x, y_fe, y_bg = split_data_into_id_x_y(data, data_type=data_type) logger.info("x.shape: " + str(x.shape)) n, m = ids.shape ewald_sum_data = np.zeros((n, 11)) if noa != -1: ewald_sum_real_energy_matrix = np.zeros((n, noa * noa)) ewald_sum_reciprocal_energy_matrix = np.zeros((n, noa * noa)) ewald_sum_total_energy_matrix = np.zeros((n, noa * noa)) ewald_sum_point_energy_matrix = np.zeros((n, noa)) for i in range(n): id = int(ids[i, 0]) print("id: {0}".format(id)) vectors, uc_atoms = read_geometry_file(data_type + "/" + str(id) + "/geometry.xyz") atom_coords, atom_labels, site_properties = convert_uc_atoms_to_input_for_pymatgen( uc_atoms) lv1 = x[i, 5] lv2 = x[i, 6] lv3 = x[i, 7] lv1_c = vector_length(vectors[0]) lv2_c = vector_length(vectors[1]) lv3_c = vector_length(vectors[2]) alpha = x[i, 8] beta = x[i, 9] gamma = x[i, 10] logger.info("lv1: {0}, lv2: {1}, lv3: {2}".format(lv1, lv2, lv3)) logger.info("lv1: {0}, lv2: {1}, lv3: {2}".format(lv1_c, lv2_c, lv3_c)) logger.info("alpha: {0}, beta: {1}, gamma: {2}".format( alpha, beta, gamma)) lattice = pymatgen.Lattice.from_parameters(a=lv1, b=lv2, c=lv3, alpha=alpha, beta=beta, gamma=gamma) structure = pymatgen.Structure(lattice, atom_labels, atom_coords, site_properties=site_properties) ewald_sum = ewald.EwaldSummation(structure) logger.info("ewald_sum: \n{0}".format(ewald_sum)) logger.info("Real space energy: {0}".format( ewald_sum.real_space_energy)) logger.info("Reciprocal energy: {0}".format( ewald_sum.reciprocal_space_energy)) logger.info("Point energy: {0}".format(ewald_sum.point_energy)) logger.info("Total energy: {0}".format(ewald_sum.total_energy)) ewald_sum_data[i][0] = ewald_sum.real_space_energy / len(uc_atoms) ewald_sum_data[i][1] = ewald_sum.reciprocal_space_energy / len( uc_atoms) ewald_sum_data[i][2] = ewald_sum.point_energy / len(uc_atoms) ewald_sum_data[i][3] = ewald_sum.total_energy / len(uc_atoms) ewald_sum_data[i][4] = np.trace(ewald_sum.real_space_energy_matrix) ewald_sum_data[i][5] = np.trace( ewald_sum.reciprocal_space_energy_matrix) ewald_sum_data[i][6] = np.trace(ewald_sum.total_energy_matrix) ewald_sum_data[i][7] = np.sum(ewald_sum.point_energy_matrix) ewald_sum_data[i][8] = np.trace( np.fliplr(ewald_sum.real_space_energy_matrix)) ewald_sum_data[i][9] = np.trace( np.fliplr(ewald_sum.reciprocal_space_energy_matrix)) ewald_sum_data[i][10] = np.trace( np.fliplr(ewald_sum.total_energy_matrix)) if noa != -1: ewald_sum_real_energy_matrix[ i, :] = ewald_sum.real_space_energy_matrix.reshape(-1, ) ewald_sum_reciprocal_energy_matrix[ i, :] = ewald_sum.reciprocal_space_energy_matrix.reshape(-1, ) ewald_sum_total_energy_matrix[ i, :] = ewald_sum.total_energy_matrix.reshape(-1, ) ewald_sum_point_energy_matrix[ i, :] = ewald_sum.point_energy_matrix.reshape(-1, ) logger.info("real_space_energy_matrix trace: " + str(ewald_sum_data[i][4])) logger.info("reciprocal_space_energy_matrix trace: " + str(ewald_sum_data[i][5])) logger.info("total_energy_matrix trace: " + str(ewald_sum_data[i][6])) ewald_sum_data = np.hstack((ids, ewald_sum_data)) if noa != -1: ewald_sum_real_energy_matrix = np.hstack( (ids, ewald_sum_real_energy_matrix)) ewald_sum_reciprocal_energy_matrix = np.hstack( (ids, ewald_sum_reciprocal_energy_matrix)) ewald_sum_total_energy_matrix = np.hstack( (ids, ewald_sum_total_energy_matrix)) ewald_sum_point_energy_matrix = np.hstack( (ids, ewald_sum_point_energy_matrix)) np.savetxt(file_name_type + "_ewald_sum_data.csv", ewald_sum_data, delimiter=",") np.save(file_name_type + "_ewald_sum_data.npy", ewald_sum_data) if noa != -1: np.save(file_name_type + "_ewald_sum_real_energy_matrix.npy", ewald_sum_real_energy_matrix) np.save(file_name_type + "_ewald_sum_reciprocal_energy_matrix.npy", ewald_sum_reciprocal_energy_matrix) np.save(file_name_type + "_ewald_sum_total_energy_matrix.npy", ewald_sum_total_energy_matrix) np.save(file_name_type + "_ewald_sum_point_energy_matrix.npy", ewald_sum_point_energy_matrix)
def ewald_matrix_features(data, data_type="train", file_name=""): # noa - number of atoms in unit cell # ids - ids of each point # x - the provides features in *.csv # y_fe - formation energy (not used here) # y_bg - band gap ids, x, y_fe, y_bg = split_data_into_id_x_y(data, data_type=data_type) n, m = ids.shape ewald_sum_data = {} for i in range(n): ewald_sum_data[i] = [[], [], [], [], []] c_id = int(ids[i, 0]) logger.info("c_id: {0}".format(c_id)) vectors, uc_atoms = read_geometry_file(data_type + "/" + str(c_id) + "/geometry.xyz") atom_coords, atom_labels, site_properties = convert_uc_atoms_to_input_for_pymatgen( uc_atoms) # Check the vectors from *.csv with the ones # from geometry.xyz. lv1 = x[c_id - 1, 5] lv2 = x[c_id - 1, 6] lv3 = x[c_id - 1, 7] lv1_c = vector_length(vectors[0]) lv2_c = vector_length(vectors[1]) lv3_c = vector_length(vectors[2]) print x.shape alpha = x[c_id - 1, 8] beta = x[c_id - 1, 9] gamma = x[c_id - 1, 10] logger.info("lv1: {0}, lv2: {1}, lv3: {2}".format(lv1, lv2, lv3)) logger.info("lv1: {0}, lv2: {1}, lv3: {2}".format(lv1_c, lv2_c, lv3_c)) logger.info("alpha: {0}, beta: {1}, gamma: {2}".format( alpha, beta, gamma)) # Create a lattice lattice = pymatgen.Lattice.from_parameters(a=lv1, b=lv2, c=lv3, alpha=alpha, beta=beta, gamma=gamma) # Create a structure representation in pymatgen structure = pymatgen.Structure(lattice, atom_labels, atom_coords, site_properties=site_properties) # Get the Ewald sum ewald_sum = ewald.EwaldSummation(structure, compute_forces=True) logger.info("ewald_sum: \n{0}".format(ewald_sum)) logger.info("Real space energy: {0}".format( ewald_sum.real_space_energy)) logger.info("Reciprocal energy: {0}".format( ewald_sum.reciprocal_space_energy)) logger.info("Point energy: {0}".format(ewald_sum.point_energy)) logger.info("Total energy: {0}".format(ewald_sum.total_energy)) # Calcualte the traces. # Note: point_energy_matrix is an array. We convert it # into a diagonal matrix and then compute the trace. ewald_sum_data[i][0] = ewald_sum.real_space_energy_matrix ewald_sum_data[i][1] = ewald_sum.reciprocal_space_energy_matrix ewald_sum_data[i][2] = ewald_sum.total_energy_matrix ewald_sum_data[i][3] = ewald_sum.point_energy_matrix ewald_sum_data[i][4] = ewald_sum.forces # Take only space group and number of total atoms from x. features = ewald_sum_data np.save(file_name, features) return features
def CalcV_M(structure): dummyPoscarLatStr = mg.core.structure.Structure(structure.lattice, ["F-"], [[0, 0, 0]]) V_M = ewald.EwaldSummation(dummyPoscarLatStr).total_energy * (-2) return V_M
def EF_H2O_wannier(structure_in, core_charges, verbose=True): #-# from copy import deepcopy from ase.neighborlist import NeighborList from ase import Atom, Atoms from pymatgen import Lattice, Structure from pymatgen.analysis import ewald structure = deepcopy(structure_in) index_Ow = get_indexes_Ow(structure) if "WANNIER_xyz" in structure.row.data.keys(): nwannier = len(structure.row.data["WANNIER_xyz"]) structure.extend( Atoms(symbols="W" * nwannier, positions=structure.row.data["WANNIER_xyz"], cell=structure.get_cell())) else: print("ERROR: Missing WANNIER_xyz") sys.exit() nl = NeighborList([1.2 / 2] * len(structure), skin=0, self_interaction=False, bothways=True) nl.update(structure) indexH = [ i for i, x in enumerate(structure.get_chemical_symbols()) if x == 'H' ] # H indexes indexW = [ i for i, x in enumerate(structure.get_chemical_symbols()) if x == 'W' ] # W indexes # Run Ewald print("Running Ewald ...") lattice = Lattice(structure.get_cell()) coords = structure.get_scaled_positions() structure.charges = [ core_charges[x] for x in structure.get_chemical_symbols() ] struct = Structure(lattice, structure.get_chemical_symbols(), coords, site_properties={"charge": structure.charges}) Ew = ewald.EwaldSummation(struct, compute_forces=True) print("Done") for iOw in index_Ow: print(" Ow idx:", iOw) print("=" * 50) vCENTER = ( structure.get_cell()[0] + structure.get_cell()[1] + structure.get_cell()[2] ) / 2. # get translation vector to put the O in the center of the box structure.translate(-structure.get_positions()[iOw] + vCENTER) # center the O in the box structure.set_scaled_positions( structure.get_scaled_positions()) # put back everything in the box neighbors = nl.get_neighbors(iOw)[0] indexH_loc = np.intersect1d(neighbors, indexH) vOH1 = structure.get_positions()[ indexH_loc[0]] - structure.get_positions()[iOw] vOH2 = structure.get_positions()[ indexH_loc[1]] - structure.get_positions()[iOw] vMid = (vOH1 / np.linalg.norm(vOH1) + vOH2 / np.linalg.norm(vOH2)) vMid = vMid / np.linalg.norm(vMid) for j in indexH_loc: vOH = structure.get_positions()[j] - structure.get_positions()[iOw] uOH = vOH / np.linalg.norm(vOH) OH = structure.get_distance(iOw, j, mic=True) # Total EF at H position EF_H = Ew.forces[j] / structure.charges[j] * eV_a2au print( " {:>2}{:<4}{:>2}{:<4} dist: {:.6f} chg{:<4} {:7.4f}".format( structure.get_chemical_symbols()[j], j, structure.get_chemical_symbols()[j], j, 0, j, structure.charges[j])) # O contribution at the H EF_OatH = structure.charges[iOw] / (4. * np.pi * e0 * (OH)**2) * (vOH / OH) * eV_a2au # Contribution from the other H indexHother = np.setdiff1d(indexH_loc, j) # the index of the other H vHH = structure.get_positions()[j] - structure.get_positions()[ indexHother[0]] HH = structure.get_distance(indexHother[0], j, mic=True) EF_HatH = structure.charges[indexHother[0]] / ( 4. * np.pi * e0 * (HH)**2) * (vHH / HH) * eV_a2au print( " {:>2}{:<4}{:>2}{:<4} dist: {:.6f} chg{:<4} {:7.4f}".format( structure.get_chemical_symbols()[j], j, structure.get_chemical_symbols()[indexHother[0]], indexHother[0], HH, indexHother[0], structure.charges[indexHother[0]])) EF_H = EF_H - EF_OatH - EF_HatH # Wannier centers indexW_loc = np.intersect1d(neighbors, indexW) for k in indexW_loc: vXH = structure.get_positions()[j] - structure.get_positions( )[k] XH = structure.get_distance(j, k, mic=True) print(" {:>2}{:<4}{:>2}{:<4} dist: {:.6f} chg{:<4} {:7.4f}". format(structure.get_chemical_symbols()[j], j, structure.get_chemical_symbols()[k], k, XH, k, structure.charges[k])) EF_XatH = structure.charges[k] / (4. * np.pi * e0 * (XH)**2) * (vXH / XH) * eV_a2au EF_H = EF_H - EF_XatH print("-" * 50) print(" H{0:<4} rOH= {1:9.6f} EF@H_along_bisector= {2:3f} a.u.". format(j, OH, np.dot(EF_H, vMid))) print(" EF@H_along_OH_bond= {0:3f} a.u.\n". format(np.dot(EF_H, uOH)))