def calc_cells_dispmats(n): """ Computes the correspondence between the SPOSCAR in the thirdorder convention and the one in the generate_conf convention. """ poscar = generate_conf.read_POSCAR("POSCAR") sposcar = thirdorder_common.gen_SPOSCAR(poscar, n[0], n[1], n[2]) sposcar2 = generate_conf.read_POSCAR("SPOSCAR") natoms = poscar["numbers"].sum() ncells = n[0] * n[1] * n[2] corresp = calc_corresp(poscar, sposcar, [n[0], n[1], n[2]]) corresp2 = calc_corresp(poscar, sposcar2, [n[0], n[1], n[2]]) print("corresp: " + str(corresp)) print("corresp2: " + str(corresp2)) M = np.zeros((ncells, natoms * ncells, natoms * ncells)) for icell in range(ncells): for iatom in range(natoms * ncells): nacell, nbcell, nccell = np.unravel_index(icell, (n[0], n[1], n[2])) i1cell, na1cell, nb1cell, nc1cell = corresp[iatom] jatom = corresp2.index([ i1cell, (na1cell + nacell) % n[0], (nb1cell + nbcell) % n[1], (nc1cell + nccell) % n[2] ]) M[icell, iatom, jatom] = 1. np.set_printoptions(threshold=sys.maxsize) N = np.zeros((ncells * natoms, ncells * natoms)) for iatom in range(natoms * ncells): i1cell, na1cell, nb1cell, nc1cell = corresp2[iatom] icell = np.ravel_multi_index((na1cell, nb1cell, nc1cell), (n[0], n[1], n[2])) N[iatom, icell * natoms + i1cell] = 1. return M, N
def calc_kinetic_term(iteration_min, weights): """ Computes the kinetic contribution to pressure from a virial-like expression """ conn = sqlite3.connect("QSCAILD.db") cur = conn.cursor() cur.execute( "SELECT id, displacements, forces, iteration FROM configurations" " WHERE iteration >=?", (iteration_min, )) config = cur.fetchall() conn.commit() conn.close() sposcar = generate_conf.read_POSCAR("SPOSCAR_CURRENT") newweights = weights.reshape((len(config), -1))[:, 0] newweights = newweights / np.sum(newweights) nruter = -np.sum(np.array([ np.sum(10. * (np.array(json.loads(c[1])) + np.ravel( np.dot( generate_conf.read_POSCAR("SPOSCAR_" + str(c[3]))["lattvec"], generate_conf.read_POSCAR("SPOSCAR_" + str(c[3]))["positions"]) - np.dot(sposcar["lattvec"], sposcar["positions"]))).reshape(-1, 3) * (np.array(json.loads(c[2])).reshape(-1, 3)), axis=0) for c in config ]) * newweights[:, np.newaxis], axis=0) return nruter / abs(np.linalg.det( sposcar["lattvec"] * 10.)) * codata.e * 1e30 * 1e-8
def prepare_fit_3rd_weights(mat_rec_ac, mat_rec_ac_3rd, M, N, enforce_acoustic, iteration_min): """ Prepare the input for the fit for a 2nd and 3rd order effective Hamiltonian. """ xdata, ydata, weights = prepare_fit_weights(mat_rec_ac, enforce_acoustic, iteration_min) print("finished preparing 2nd order part of the fit") conn = sqlite3.connect("QSCAILD.db") cur = conn.cursor() cur.execute( "SELECT id, displacements, iteration " "FROM configurations WHERE iteration >=?", (iteration_min, )) config = cur.fetchall() conn.commit() conn.close() sposcar = generate_conf.read_POSCAR("SPOSCAR_CURRENT") print("start preparing 3rd order part") xdata_3rd = [] natoms = int(len(json.loads(config[0][1])) / 3) for k in range(mat_rec_ac_3rd.shape[0]): print("preparing data number " + str(k)) xdata_int = [] fcs_3rd_full = mat_rec_ac_3rd[k] for c in config: sposcar_old = generate_conf.read_POSCAR("SPOSCAR_" + str(c[2])) newdisp = np.array(json.loads(c[1])) + np.ravel( np.dot(sposcar_old["lattvec"], sposcar_old["positions"]) - np.dot(sposcar["lattvec"], sposcar["positions"])) xdata_int.append(calc_3rd_forces(fcs_3rd_full, M, N, newdisp)) if enforce_acoustic: for alpha in range(3): disp = np.zeros((natoms, 3)) disp[:, alpha] = 0.01 * np.ones(natoms).T xdata_int.append( calc_3rd_forces(fcs_3rd_full, M, N, np.ravel(disp))) xdata_3rd.append(np.ravel(xdata_int)) xdata_3rd = np.concatenate((xdata, np.transpose(np.array(xdata_3rd))), axis=1) return [xdata_3rd, ydata, weights]
def read_3rd_fcs_asinfile(fcs_file, poscar_file): """ Read a set of anharmonic force constants from a file. """ poscar = generate_conf.read_POSCAR(poscar_file) lattvec = poscar["lattvec"] * 10. fcs_3rd = [] atom_info = [] R_j = [] R_k = [] abc = [] with open(fcs_file, "r") as f: nblocks = int(next(f).strip()) tmp = np.empty((3, 2)) for iblock in range(nblocks): next(f) next(f) tmp[:, 0] = [float(i) for i in next(f).split()] tmp[:, 1] = [float(i) for i in next(f).split()] Rj = np.round(sp.linalg.solve(lattvec, tmp[:, 0])) Rk = np.round(sp.linalg.solve(lattvec, tmp[:, 1])) ijk = [int(i) - 1 for i in next(f).split()] for il in range(27): fields = next(f).split() c1, c2, c3 = [int(i) - 1 for i in fields[:3]] atom_info.append(ijk) R_j.append(Rj) R_k.append(Rk) abc.append([c1, c2, c3]) fcs_3rd.append(float(fields[3])) return np.array(fcs_3rd), np.array(atom_info), np.array(R_j), np.array( R_k), np.array(abc)
def read_FORCE_CONSTANTS(sposcar_file, fcs_file): """ Read and return the information contained in a FORCE_CONSTANTS file, which must correspond to the provided sposcar object. """ #in phonopy comments: #force_constants[ i, j, a, b ] # i: Atom index of finitely displaced atom. # j: Atom index at which force on the atom is measured. # a, b: Cartesian direction indices = (0, 1, 2) for i and j, respectively sposcar = generate_conf.read_POSCAR(sposcar_file) with open(fcs_file, "r") as f: n = int(next(f).strip()) nsatoms = len(sposcar["types"]) if n != nsatoms: raise ValueError( "file {} does not match the provided SPOSCAR object".format( fcs_file)) fullmatrix = np.empty((nsatoms, nsatoms, 3, 3)) for iat1 in range(nsatoms): for iat2 in range(nsatoms): p1, p2 = [int(i) for i in next(f).split()] if p1 != iat1 + 1 or p2 != iat2 + 1: raise ValueError( "invalid index in file {}".format(fcs_file)) for icoord in range(3): fullmatrix[iat1, iat2, icoord, :] = [ float(j) for j in next(f).split() ] return fullmatrix
def save_symmetry_information_3rd(n3rdorder, third, symm_acoustic=True): """ Computes and saves the 2nd and 3rd order symmetry matrices. """ (natoms, crotations, equivalences, kernels, irreducible, todo) = get_symmetry_information("SPOSCAR") if (symm_acoustic): ker_ac, nirr_ac = acoustic_sum_rule(natoms, crotations, equivalences, kernels, irreducible, todo) else: nirr_ac = len(todo) ker_ac = np.identity(nirr_ac) mat_rec_ac = [ reconstruct_fc_acoustic( natoms, ker_ac, np.array([int(j == k) for j in range(nirr_ac)]), crotations, equivalences, kernels, irreducible, symm_acoustic) for k in range(nirr_ac) ] np.save( "../mat_rec_ac_2nd_" + str(n3rdorder[0]) + "x" + str(n3rdorder[1]) + "x" + str(n3rdorder[2]) + ".npy", mat_rec_ac) if not third: return poscar = generate_conf.read_POSCAR("POSCAR") sposcar = thirdorder_common.gen_SPOSCAR(poscar, n3rdorder[0], n3rdorder[1], n3rdorder[2]) if (symm_acoustic): (ker_ac_3rd, nirr_ac_3rd, wedge, list4, dmin, nequi, shifts, frange) = thirdorder_save.save("save_sparse", n3rdorder[0], n3rdorder[1], n3rdorder[2], n3rdorder[3]) with open('out_sym', 'a') as file: file.write("3rd order number of irreducible elements after " + "acoustic sum rule: " + str(nirr_ac_3rd) + "\n") np.save( "../ker_ac_3rd_" + str(n3rdorder[0]) + "x" + str(n3rdorder[1]) + "x" + str(n3rdorder[2]) + "_" + str(n3rdorder[3]) + ".npy", ker_ac_3rd) else: wedge, list4, dmin, nequi, shifts, frange = thirdorder_save.save( "return", n3rdorder[0], n3rdorder[1], n3rdorder[2], n3rdorder[3]) nirr_ac_3rd = 0 for ii in range(wedge.nlist): print("nindependentbasis: " + str(wedge.nindependentbasis[ii])) nirr_ac_3rd += wedge.nindependentbasis[ii] with open('out_sym', 'a') as file: file.write("3rd order number of irreducible elements without" + " acoustic sum rule: " + str(nirr_ac_3rd) + "\n") ker_ac_3rd = np.identity(nirr_ac_3rd) mat_rec_ac_3rd = calc_mat_rec_ac_3rd(poscar, sposcar, ker_ac_3rd, nirr_ac_3rd, wedge, list4, n3rdorder, symm_acoustic) np.save( "../mat_rec_ac_3rd_" + str(n3rdorder[0]) + "x" + str(n3rdorder[1]) + "x" + str(n3rdorder[2]) + "_" + str(n3rdorder[3]) + ".npy", mat_rec_ac_3rd) return
def calc_energy_pressure(f_grun, m_grun, T, poscar_file): """ Calculate the energy associated to the pressure estimated from the Gruneisen parameters. """ poscar = generate_conf.read_POSCAR(poscar_file) nBE = np.array([fBE(f, T) + 0.5 for f in f_grun]) nmodes = poscar["numbers"].sum() * 3. volume = abs(np.linalg.det(poscar["lattvec"] * 10.)) return nmodes * np.mean(codata.h * m_grun * 1e12 * nBE[:, np.newaxis]) / volume * 1e30 * 1e-8 / 3.
def write_displacement_matrix(poscar_file, fcs_file, T, n, use_smalldisp, imaginary_freq, grid): """ Write the displacement matrix depending of T, force constants and structure, integrated over the Brillouin zone. """ SYMPREC = 1e-5 NQ = grid if not os.path.isfile(poscar_file): sys.exit("The specified POSCAR file does not exist.") na, nb, nc = [int(i) for i in n] if min(na, nb, nc) < 1: sys.exit("All dimensions must be positive integers") poscar = generate_conf.read_POSCAR(poscar_file) natoms = poscar["numbers"].sum() ntot = na * nb * nc * natoms nmodes = 3 * natoms ncells = na * nb * nc matrix = np.zeros((ncells * nmodes, ncells * nmodes), dtype=np.complex128) local_matrix = np.zeros((ncells * nmodes, ncells * nmodes), dtype=np.complex128) if use_smalldisp: for idiag in range(ncells * nmodes): matrix[idiag, idiag] = 0.000001 return matrix if not os.path.isfile(fcs_file): sys.exit("The specified FORCE_CONSTANTS file does not exist.") supercell_matrix = np.diag([na, nb, nc]) structure = phonopy.interface.read_crystal_structure(poscar_file, "vasp")[0] fc = phonopy.file_IO.parse_FORCE_CONSTANTS(fcs_file) phonon = phonopy.Phonopy( structure, supercell_matrix, primitive_matrix=None, factor=phonopy.units.VaspToTHz, dynamical_matrix_decimals=None, force_constants_decimals=None, symprec=SYMPREC, is_symmetry=True, log_level=0) if os.path.isfile("BORN"): nac_params = phonopy.file_IO.get_born_parameters( open("BORN"), phonon.get_primitive(), phonon.get_primitive_symmetry()) phonon.set_nac_params(nac_params=nac_params) phonon.set_force_constants(fc) masses = phonon.get_supercell().get_masses( ) * codata.physical_constants["atomic mass constant"][0] qpoints = create_mesh(NQ) nqpoints = qpoints.shape[0] # Initializations and preliminaries comm = MPI.COMM_WORLD # get MPI communicator object size = comm.size # total number of processes rank = comm.rank # rank of this process full_qlist = list(range(nqpoints)) qlist = full_qlist[rank::size] for qpt in qlist: local_matrix += qpoint_worker((qpoints[qpt, :], phonon, T, na, nb, nc, imaginary_freq, poscar["positions"])) # Reduce all qpoints comm.Reduce(local_matrix, matrix, op=MPI.SUM, root=0) if rank == 0: matrix *= codata.hbar / 2. / nqpoints / 2. / np.pi / 1e12 # m**2 for i, j in itertools.product( range(ncells * nmodes), range(ncells * nmodes)): matrix[i, j] /= np.sqrt(masses[i // 3] * masses[j // 3]) matrix = 1e18 * matrix.real # nm**2 comm.Barrier() return matrix
def write_displacement_matrix_gamma(sposcar_file, fcs_file, T, n, use_smalldisp, imaginary_freq): """ Writes the displacement matrix depending of T, force constants and structure, using only the gamma-point of the supercell. """ SYMPREC = 1e-5 if not os.path.isfile(sposcar_file): sys.exit("The specified POSCAR file does not exist.") na, nb, nc = [1, 1, 1] poscar = generate_conf.read_POSCAR(sposcar_file) natoms = poscar["numbers"].sum() ntot = na * nb * nc * natoms nmodes = 3 * natoms ncells = na * nb * nc matrix = np.zeros((ncells * nmodes, ncells * nmodes), dtype=np.complex128) if use_smalldisp: for idiag in range(ncells * nmodes): matrix[idiag, idiag] = 0.000001 return matrix if not os.path.isfile(fcs_file): sys.exit("The specified FORCE_CONSTANTS file does not exist.") supercell_matrix = np.diag([na, nb, nc]) structure = phonopy.interface.read_crystal_structure(sposcar_file, "vasp")[0] fc = phonopy.file_IO.parse_FORCE_CONSTANTS(fcs_file) phonon = phonopy.Phonopy( structure, supercell_matrix, primitive_matrix=None, factor=phonopy.units.VaspToTHz, dynamical_matrix_decimals=None, force_constants_decimals=None, symprec=SYMPREC, is_symmetry=True, log_level=0) if os.path.isfile("BORN"): nac_params = phonopy.file_IO.get_born_parameters( open("BORN"), phonon.get_primitive(), phonon.get_primitive_symmetry()) phonon.set_nac_params(nac_params=nac_params) phonon.set_force_constants(fc) masses = phonon.get_supercell().get_masses( ) * codata.physical_constants["atomic mass constant"][0] nqpoints = 1 print("nqpoints: " + repr(nqpoints)) matrix = qpoint_worker(([0., 0., 0.], phonon, T, na, nb, nc, imaginary_freq, poscar["positions"])) matrix *= codata.hbar / 2. / nqpoints / 2. / np.pi / 1e12 # m**2 for i, j in itertools.product( range(ncells * nmodes), range(ncells * nmodes)): matrix[i, j] /= np.sqrt(masses[i // 3] * masses[j // 3]) matrix = 1e18 * matrix.real # nm**2 return matrix
def write_mode_gruneisen_gamma(poscar_file, sposcar_file, n, fcs_file, fcs_3rd_file, imaginary_freq, filename): """ Write the gruneisen parameters depending of T, force constants and structure, using only the gamma point of the supercell. """ SYMPREC = 1e-5 NQ = 1 if not os.path.isfile(poscar_file): sys.exit("Gruneisen: the specified POSCAR file does not exist.") poscar = generate_conf.read_POSCAR(poscar_file) sposcar = generate_conf.read_POSCAR(sposcar_file) corresp = symmetry.calc_corresp(poscar, sposcar, n) ncells = n[0] * n[1] * n[2] natoms = poscar["numbers"].sum() nmodes = 3 * natoms * ncells supercell_matrix = np.diag([1, 1, 1]) if not os.path.isfile(fcs_file): sys.exit("The specified FORCE_CONSTANTS file does not exist.") if not os.path.isfile(fcs_3rd_file): sys.exit("The specified FORCE_CONSTANTS_3RD file does not exist.") fcs_3rd, atom_info, R_j, R_k, abc = read_3rd_fcs_asinfile( fcs_3rd_file, poscar_file) nblocks = len(fcs_3rd) poscar_positions = sp.dot(poscar["lattvec"], poscar["positions"]).T * 10. cartesian_positions = np.array([ sp.dot(poscar["lattvec"], R_k[iblock])[abc[iblock, 2]] * 10. + poscar_positions[atom_info[iblock, 2], abc[iblock, 2]] for iblock in range(nblocks) ]) structure = phonopy.interface.read_crystal_structure(sposcar_file, "vasp")[0] fc = phonopy.file_IO.parse_FORCE_CONSTANTS(fcs_file) phonon = phonopy.Phonopy(structure, supercell_matrix, primitive_matrix=None, factor=phonopy.units.VaspToTHz, dynamical_matrix_decimals=None, force_constants_decimals=None, symprec=SYMPREC, is_symmetry=True, log_level=0) if os.path.isfile("BORN"): nac_params = phonopy.file_IO.get_born_parameters( open("BORN"), phonon.get_primitive(), phonon.get_primitive_symmetry()) phonon.set_nac_params(nac_params=nac_params) phonon.set_force_constants(fc) masses = phonon.get_unitcell().get_masses() massesi = np.array([ masses[corresp.index([atom_info[iblock, 0], 0, 0, 0])] for iblock in range(nblocks) ]) massesj = np.array([ masses[corresp.index([atom_info[iblock, 1], 0, 0, 0])] for iblock in range(nblocks) ]) print("nqpoints: " + str(NQ)) mesh = [[0., 0., 0.]] w_grun = [] m_grun = [] f_grun = [] tot_cv = 0. r = range(nmodes) for q in mesh: f, psi = phonon.get_frequencies_with_eigenvectors(q) factorj = 1.0 for im in r: if (f[im] < -1.e-4): print("ATTENTION: IMAGINARY FREQUENCIES ->" " CONVERTED TO POSITIVE VALUE") if imaginary_freq == -1: f[im] = abs(f[im]) else: f[im] = imaginary_freq if (f[im] > 1.e-4): lpsi = psi[:, im].reshape(-1, 3) psii = np.conj( np.array([ lpsi[corresp.index([atom_info[iblock, 0], 0, 0, 0]), abc[iblock, 0]] for iblock in range(nblocks) ])) psij = np.array([ lpsi[corresp.index([ atom_info[iblock, 1], R_j[iblock, 0] % n[0], R_j[iblock, 1] % n[1], R_j[iblock, 2] % n[2] ]), abc[iblock, 1]] for iblock in range(nblocks) ]) m_gruni = mode_gruneisen(f[im], psii, psij, massesi, massesj, cartesian_positions, fcs_3rd, factorj).real * ncells m_grun.append(m_gruni) f_grun.append(f[im]) else: m_grun.append(np.array([0., 0., 0.])) f_grun.append(f[im]) with open(filename, 'w') as f: for i in range(len(f_grun)): f.write( str(f_grun[i]) + ' ' + str(m_grun[i][0]) + ' ' + str(m_grun[i][1]) + ' ' + str(m_grun[i][2]) + '\n') m_grun = np.array(m_grun) f_grun = np.array(f_grun) return f_grun, m_grun
def write_mode_gruneisen(poscar_file, n, fcs_file, fcs_3rd_file, imaginary_freq, grid, filename): """ Write the gruneisen parameters depending of T, force constants and structure, in the whole Brillouin zone. """ SYMPREC = 1e-5 if not os.path.isfile(poscar_file): sys.exit("Gruneisen: the specified POSCAR file does not exist.") poscar = generate_conf.read_POSCAR(poscar_file) ncells = n[0] * n[1] * n[2] natoms = poscar["numbers"].sum() nmodes = 3 * natoms supercell_matrix = np.diag([n[0], n[1], n[2]]) if not os.path.isfile(fcs_file): sys.exit("The specified FORCE_CONSTANTS file does not exist.") if not os.path.isfile(fcs_3rd_file): sys.exit("The specified FORCE_CONSTANTS_3RD file does not exist.") fcs_3rd, atom_info, R_j, R_k, abc = read_3rd_fcs_asinfile( fcs_3rd_file, poscar_file) nblocks = len(fcs_3rd) poscar_positions = sp.dot(poscar["lattvec"], poscar["positions"]).T * 10. cartesian_positions = np.array([ sp.dot(poscar["lattvec"], R_k[iblock])[abc[iblock, 2]] * 10. + poscar_positions[atom_info[iblock, 2], abc[iblock, 2]] for iblock in range(nblocks) ]) structure = phonopy.interface.read_crystal_structure(poscar_file, "vasp")[0] fc = phonopy.file_IO.parse_FORCE_CONSTANTS(fcs_file) phonon = phonopy.Phonopy(structure, supercell_matrix, primitive_matrix=None, factor=phonopy.units.VaspToTHz, dynamical_matrix_decimals=None, force_constants_decimals=None, symprec=SYMPREC, is_symmetry=True, log_level=0) if os.path.isfile("BORN"): nac_params = phonopy.file_IO.get_born_parameters( open("BORN"), phonon.get_primitive(), phonon.get_primitive_symmetry()) phonon.set_nac_params(nac_params=nac_params) phonon.set_force_constants(fc) masses = phonon.get_unitcell().get_masses() massesi = masses[atom_info[:, 0]] massesj = masses[atom_info[:, 1]] NQ = grid mesh = create_mesh(NQ) nqpoints = mesh.shape[0] m_grun = [] f_grun = [] r = range(nmodes) # Initializations and preliminaries comm = MPI.COMM_WORLD # get MPI communicator object size = comm.size # total number of processes rank = comm.rank # rank of this process # Scatter qpoints across cores. full_qlist = list(range(nqpoints)) qlist = full_qlist[rank::size] for qpt in qlist: q = mesh[qpt, :] f, psi = phonon.get_frequencies_with_eigenvectors(q) factor = np.exp(2j * np.pi * np.dot(q, poscar["positions"])) factorj = np.exp(2j * np.pi * np.dot(R_j, q)) for im in r: if (f[im] < -1.e-4): print("ATTENTION: IMAGINARY FREQUENCIES ->" " CONVERTED TO POSITIVE VALUE") if imaginary_freq == -1: f[im] = abs(f[im]) else: f[im] = imaginary_freq if (f[im] > 1.e-4): lpsi = psi[:, im].reshape(-1, 3) * factor[:, np.newaxis] psii = np.conj( np.array([ lpsi[atom_info[iblock, 0], abc[iblock, 0]] for iblock in range(nblocks) ])) psij = np.array([ lpsi[atom_info[iblock, 1], abc[iblock, 1]] for iblock in range(nblocks) ]) m_gruni = mode_gruneisen(f[im], psii, psij, massesi, massesj, cartesian_positions, fcs_3rd, factorj).real m_grun.append(m_gruni) f_grun.append(f[im]) else: m_grun.append(np.array([0., 0., 0.])) f_grun.append(f[im]) m_grun = np.array(m_grun) f_grun = np.array(f_grun) # Gather all qpoints m_grun = comm.gather(m_grun, root=0) f_grun = comm.gather(f_grun, root=0) if rank == 0: m_grun = np.concatenate(m_grun) f_grun = np.concatenate(f_grun) with open(filename, 'w') as f: for i in range(f_grun.shape[0]): f.write( str(f_grun[i]) + ' ' + str(m_grun[i][0]) + ' ' + str(m_grun[i][1]) + ' ' + str(m_grun[i][2]) + '\n') m_grun = comm.bcast(m_grun, root=0) f_grun = comm.bcast(f_grun, root=0) return f_grun, m_grun
def fit_force_constants(nconf, nfits, T, n, cutoff, third, use_pressure, pressure, use_smalldisp, calc_symm, symm_acoustic, imaginary_freq, enforce_acoustic, grid, tolerance, pdiff, memory, mixing): """ Main function that monitors the self-consistency loop. """ iteration = 0 write_gruneisen = False if not os.path.isfile("iteration"): iteration = 1 if os.path.isfile("QSCAILD.db"): with open("finished", "w") as file: file.write( "finished: error\n" "Problem: no previous iteration but database already present," " remove file QSCAILD.db") comm.Abort() sys.exit( "Problem: no previous iteration but database already present," " remove file QSCAILD.db") else: if rank == 0: shutil.copy("POSCAR", "POSCAR_CURRENT") shutil.copy("SPOSCAR", "SPOSCAR_CURRENT") print("Create table in database") conn = sqlite3.connect("QSCAILD.db") cur = conn.cursor() cur.execute( "CREATE TABLE configurations (id integer, iteration" " integer, displacements text, probability real," " current_proba real, forces text, energy real," " har_forces text, har_energy real)") conn.commit() conn.close() if calc_symm: symmetry.save_symmetry_information_3rd( [n[0], n[1], n[2], cutoff], third, symm_acoustic) renew_configurations(nconf, T, n, iteration, "POSCAR", "SPOSCAR", "FORCE_CONSTANTS", use_smalldisp, imaginary_freq, grid) comm.Barrier() if rank == 0: with open("iteration", "w") as f: f.write(str(iteration) + "\n") return if rank == 0: with open("iteration", "r") as f: iteration = int(f.readline().split()[0]) if not os.path.isfile("QSCAILD.db"): with open("finished", "w") as file: file.write( "finished: error\n" "Problem: previous iterations but no database is present," " remove file iteration") comm.Abort() sys.exit("Problem: previous iterations but no database is present," " remove file iteration") with open("out_energy", 'a') as file: file.write("iteration: " + str(iteration) + "\n") with open("out_fit", 'a') as file: file.write("iteration: " + str(iteration) + "\n") gradient.store_vasp_forces_energy(iteration) iteration_min = int(math.floor(iteration * (1.0 - memory))) if os.path.isfile("FORCE_CONSTANTS_CURRENT"): shutil.copy("FORCE_CONSTANTS_CURRENT", "FORCE_CONSTANTS_PREVIOUS") print("Load 2nd order symmetry information") mat_rec_ac = np.load("../mat_rec_ac_2nd_" + str(n[0]) + "x" + str(n[1]) + "x" + str(n[2]) + ".npy", allow_pickle = True) nirr_ac = len(mat_rec_ac) poscar = generate_conf.read_POSCAR("POSCAR") natoms = poscar["numbers"].sum() * n[0] * n[1] * n[2] if third: sposcar = thirdorder_common.gen_SPOSCAR(poscar, n[0], n[1], n[2]) print("Load 3rd order symmetry information") wedge, list4, dmin, nequi, shifts, frange = thirdorder_save.save( "return", n[0], n[1], n[2], cutoff) mat_rec_ac_3rd = np.load("../mat_rec_ac_3rd_" + str(n[0]) + "x" + str(n[1]) + "x" + str(n[2]) + "_" + str(cutoff) + ".npy", allow_pickle = True)[()] print(("shape: " + str(mat_rec_ac_3rd.shape))) if (symm_acoustic): ker_ac_3rd = np.load("../ker_ac_3rd_" + str(n[0]) + "x" + str(n[1]) + "x" + str(n[2]) + "_" + str(cutoff) + ".npy", allow_pickle = True) else: ker_ac_3rd = np.identity(mat_rec_ac_3rd.shape[0]) M, N = symmetry.calc_cells_dispmats(n) if third: x_data, y_data, weights = gradient.prepare_fit_3rd_weights( mat_rec_ac, mat_rec_ac_3rd, M, N, enforce_acoustic, iteration_min) else: x_data, y_data, weights = gradient.prepare_fit_weights( mat_rec_ac, enforce_acoustic, iteration_min) clf = linear_model.LinearRegression(fit_intercept=False) clf.fit(x_data, y_data, weights) if third: coef_2nd = clf.coef_[:nirr_ac] coef_3rd = clf.coef_[nirr_ac:] else: coef_2nd = clf.coef_ with open("out_fit", 'a') as file: file.write("fit 2nd: " + str(coef_2nd.tolist()) + "\n") if third: file.write("fit 3rd: " + str(coef_3rd.tolist()) + "\n") file.write("score: "+str(clf.score(x_data,y_data,weights))+"\n") force_constants = symmetry.reconstruct_fc_acoustic_frommat( mat_rec_ac, np.array(coef_2nd)) gradient.print_FORCE_CONSTANTS(force_constants, "FORCE_CONSTANTS_FIT_" + str(iteration)) if iteration == 1 and not use_smalldisp: force_constants = ( 1.0 - mixing ) * force_constants + mixing * gradient.read_FORCE_CONSTANTS( "SPOSCAR", "FORCE_CONSTANTS") elif not use_smalldisp: force_constants = ( 1.0 - mixing ) * force_constants + mixing * gradient.read_FORCE_CONSTANTS( "SPOSCAR_CURRENT", "FORCE_CONSTANTS_CURRENT") gradient.print_FORCE_CONSTANTS(force_constants, "FORCE_CONSTANTS_CURRENT") if third: phifull = symmetry.reconstruct_3rd_fcs(poscar, sposcar, ker_ac_3rd, coef_3rd, wedge, list4, symm_acoustic) thirdorder_common.write_ifcs( phifull, poscar, sposcar, dmin, nequi, shifts, frange, "FORCE_CONSTANTS_FIT_3RD_" + str(iteration)) thirdorder_common.write_ifcs(phifull, poscar, sposcar, dmin, nequi, shifts, frange, "FORCE_CONSTANTS_CURRENT_3RD") poscar_current = generate_conf.read_POSCAR("POSCAR_CURRENT") sposcar_current = generate_conf.read_POSCAR("SPOSCAR_CURRENT") factor = np.array([1.0, 1.0, 1.0]) os.sync() comm.Barrier() #Compute external pressure and updates lattice parameter if necessary if use_pressure in ['cubic', 'tetragonal', 'orthorombic']: if os.path.isfile("POSCAR_PARAM") and os.path.isfile( "SPOSCAR_PARAM") and rank == 0: poscar_param = generate_conf.read_POSCAR("POSCAR_PARAM") poscar_param["lattvec"] = poscar_current["lattvec"] generate_conf.write_POSCAR(poscar_param, "POSCAR_PARAM") sposcar_param = generate_conf.read_POSCAR("SPOSCAR_PARAM") sposcar_param["lattvec"] = sposcar_current["lattvec"] generate_conf.write_POSCAR(sposcar_param, "SPOSCAR_PARAM") if grid > 0 and write_gruneisen and third: f_grun, m_grun = gruneisen.write_mode_gruneisen( "POSCAR_CURRENT", n, "FORCE_CONSTANTS_CURRENT", "FORCE_CONSTANTS_CURRENT_3RD", imaginary_freq, grid, "mode_gruneisen") if rank == 0: if grid == 0 and write_gruneisen and third: f_grun, m_grun = gruneisen.write_mode_gruneisen_gamma( "POSCAR_CURRENT", "SPOSCAR_CURRENT", n, "FORCE_CONSTANTS_CURRENT", "FORCE_CONSTANTS_CURRENT_3RD", imaginary_freq, "mode_gruneisen") if write_gruneisen and third: gruneisen.write_weighted_gruneisen( f_grun, m_grun, [Ti * 100. for Ti in range(1, 16)], "weighted_gruneisen") potential_pressure = np.diag( gradient.calc_mean_stress_weights(iteration_min, weights)) kinetic_pressure = gradient.calc_kinetic_term( iteration_min, weights) mean_pressure = potential_pressure + kinetic_pressure for i in range(3): if (mean_pressure[i] > pressure[i] + pdiff / 2.): factor[i] = 1. + 0.001 * (min( (mean_pressure[i] - pressure[i]) / 10., 4.)) elif (mean_pressure[i] < pressure[i] - pdiff / 2.): factor[i] = 1. - 0.001 * (min( (pressure[i] - mean_pressure[i]) / 10., 4.)) #Symmetrize stress tensor if use_pressure == 'cubic': factor = np.array( [np.mean(factor), np.mean(factor), np.mean(factor)]) if use_pressure == 'tetragonal': factor = np.array([ 0.5 * factor[0] + 0.5 * factor[1], 0.5 * factor[0] + 0.5 * factor[1], factor[2] ]) if use_pressure == 'cubic': sposcar_current[ "lattvec"] = sposcar_current["lattvec"] * factor[0] poscar_current[ "lattvec"] = poscar_current["lattvec"] * factor[0] else: # Can only handle diagonal lattice vectors if the unit cell # is non-cubic for i in range(3): sposcar_current["lattvec"][ i, i] = sposcar_current["lattvec"][i, i] * factor[i] poscar_current["lattvec"][ i, i] = poscar_current["lattvec"][i, i] * factor[i] # Make parameter update of the poscar using non-harmonic part # of forces if os.path.isfile("POSCAR_PARAM") and os.path.isfile( "SPOSCAR_PARAM"): param_grad = gradient.calc_delta_Ep_weights( force_constants, sposcar_param, iteration_min, weights) with open("out_parameter", 'a') as file: file.write("iteration: " + str(iteration) + "\n") file.write("parameter gradient: " + str(param_grad) + "\n") poscar_current[ "positions"] -= poscar_param["positions"] * param_grad sposcar_current[ "positions"] -= sposcar_param["positions"] * param_grad generate_conf.write_POSCAR(poscar_current, "POSCAR_CURRENT") generate_conf.write_POSCAR(sposcar_current, "SPOSCAR_CURRENT") if use_pressure in ['cubic', 'tetragonal', 'orthorombic']: with open("out_volume", 'a') as file: file.write("iteration: " + str(iteration) + "\n") file.write("kinetic pressure: " + str(kinetic_pressure.tolist()) + "\n") file.write("potential pressure: " + str(potential_pressure.tolist()) + "\n") file.write("mean pressure: " + str(mean_pressure.tolist()) + "\n") file.write("lattice vectors: " + str(poscar_current["lattvec"].tolist()) + "\n") else: mean_pressure = None mean_pressure = comm.bcast(mean_pressure, root=0) os.sync() iteration = comm.bcast(iteration, root=0) comm.Barrier() if iteration >= nfits: if rank == 0: with open("finished", "w") as file: file.write("finished: maximum iteration number\n") return if test_convergence(iteration, tolerance): if not use_pressure in ['cubic', 'tetragonal', 'orthorombic']: if rank == 0: with open("finished", "w") as file: file.write("finished: obtained convergence\n") return elif np.amax(np.abs(mean_pressure - pressure)) < pdiff: if rank == 0: with open("finished", "w") as file: file.write("finished: obtained convergence\n") return iteration += 1 renew_configurations(nconf, T, n, iteration, "POSCAR_CURRENT", "SPOSCAR_CURRENT", "FORCE_CONSTANTS_CURRENT", use_smalldisp, imaginary_freq, grid) if rank == 0: with open("iteration", "w") as f: f.write(str(iteration) + "\n") return
def prepare_fit_weights(mat_rec_ac, enforce_acoustic, iteration_min): """ Prepare the input for the fit for a 2nd order effective Hamiltonian. """ conn = sqlite3.connect("QSCAILD.db") cur = conn.cursor() cur.execute( "SELECT id, displacements, forces, probability, current_proba," " iteration FROM configurations WHERE iteration >=?", (iteration_min, )) config = cur.fetchall() conn.commit() conn.close() ydata = [] xdata = [] weights = [] natoms = int(len(json.loads(config[0][1])) / 3) sposcar = generate_conf.read_POSCAR("SPOSCAR_CURRENT") for k in range(len(mat_rec_ac)): xdata_int = [] for c in config: sposcar_old = generate_conf.read_POSCAR("SPOSCAR_" + str(c[5])) newdisp = np.array(json.loads(c[1])) + np.ravel( np.dot(sposcar_old["lattvec"], sposcar_old["positions"]) - np.dot(sposcar["lattvec"], sposcar["positions"])) disp = 10. * newdisp ##Put displacements in Angstroms xdata_int.append(-mat_rec_ac[k].dot(disp)) if enforce_acoustic: for alpha in range(3): disp = np.zeros((natoms, 3)) disp[:, alpha] = 0.01 * np.ones(natoms).T xdata_int.append(-mat_rec_ac[k].dot(np.ravel(disp))) xdata.append(np.ravel(xdata_int)) xdata = np.transpose(np.array(xdata)) for c in config: ydata.append(np.ravel(np.array(json.loads(c[2])))) print("weight of config " + str(c[0]) + ": " + str(np.exp(c[4] - c[3]))) weights.append(np.exp(c[4] - c[3]) * np.ones(natoms * 3)) if enforce_acoustic: for alpha in range(3): ydata.append(np.zeros(natoms * 3)) weights.append(10. * np.ones(natoms * 3)) ydata = np.array(ydata) weights = np.array(weights) # remove mean force where it is not zero by symmetry if os.path.isfile("POSCAR_PARAM") and os.path.isfile("SPOSCAR_PARAM"): sposcar_param = generate_conf.read_POSCAR("SPOSCAR_PARAM") cartesian_positions = np.ravel( sp.dot(sposcar_param["lattvec"], sposcar_param["positions"]).T * 10.) mean_forces = np.sum(ydata * weights, axis=0) / np.sum(weights, axis=0) delta_Ep = np.mean(mean_forces * cartesian_positions) with np.errstate(divide='ignore', invalid='ignore'): symm_mean_force = np.divide(delta_Ep, cartesian_positions) symm_mean_force[~np.isfinite(symm_mean_force)] = 0 with open("out_fit", "a") as file: file.write("mean_forces: " + str(mean_forces.tolist()) + "\n") file.write("symm_mean_force: " + str(symm_mean_force.tolist()) + "\n") ydata -= symm_mean_force[np.newaxis, :] ydata = np.ravel(ydata) weights = np.ravel(weights) return [xdata, ydata, weights]