Beispiel #1
0
def test_convergence(iteration, tolerance):
    """
    Test convergence of the fitted force constants.
    """
    if iteration < 2:
        return False
    if rank == 0:
        fcs_current = gradient.read_FORCE_CONSTANTS("SPOSCAR_CURRENT",
                                                    "FORCE_CONSTANTS_CURRENT")
        fcs_previous = gradient.read_FORCE_CONSTANTS(
            "SPOSCAR_CURRENT", "FORCE_CONSTANTS_PREVIOUS")
        with open("out_convergence", 'a') as file:
            file.write("iteration: " + str(iteration) + "\n")
            file.write("fcs max absolute difference: " +
                       str(np.amax(np.absolute(fcs_current - fcs_previous))) +
                       "\n")
            file.write("fcs mean absolute difference: " +
                       str(np.mean(np.absolute(fcs_current - fcs_previous))) +
                       "\n")
            file.write("fcs max relative difference: " + str(
                np.nanmax(
                    np.divide(
                        np.absolute(fcs_current - fcs_previous),
                        np.absolute(fcs_previous)))) + "\n")
            nruter = np.allclose(fcs_current, fcs_previous, atol=tolerance)
    else:
        nruter = None
    nruter = comm.bcast(nruter, root=0)
    return nruter
Beispiel #2
0
def compute_irr_fc(sposcar_file,
                   fcs_file,
                   mat_rec_ac_file,
                   mat_rec_ac_reshaped_file="mat_rec_ac_2nd_reshaped.npy",
                   calc_reshape=True):
    """
    Computes the 2nd order irreducible elements from a force constants file
    (correspondence not tested in this latest version).
    """
    fcs_to_fit = gradient.read_FORCE_CONSTANTS(sposcar_file, fcs_file)
    ntot = len(fcs_to_fit)
    mat_rec_ac = np.load(mat_rec_ac_file)
    if calc_reshape:
        reshape_mat_rec_ac(mat_rec_ac, mat_rec_ac_reshaped_file, ntot)
    mat_rec_ac_new = np.load(mat_rec_ac_reshaped_file)[()]
    print("computing irreducible elements")
    fit = sp.sparse.linalg.lsqr(mat_rec_ac_new,
                                np.rollaxis(fcs_to_fit, 2, 1).ravel())
    irr_fc_ac = fit[0]
    print("printing force constants to file")
    force_constants = reconstruct_fc_acoustic_frommat(mat_rec_ac, irr_fc_ac)
    gradient.print_FORCE_CONSTANTS(force_constants, "FORCE_CONSTANTS_REC")
    return irr_fc_ac
Beispiel #3
0
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