Beispiel #1
0
    def test_double_swaps_ternary( self ):
        if ( not has_ase_with_ce ): # Disable this test
            self.skipTest("ASE version has not cluster expansion")
            return

        db_name = "test_db_ternary.db"
        conc_args = {
            "conc_ratio_min_1":[[4,0,0]],
            "conc_ratio_max_1":[[0,4,0]],
            "conc_ratio_min_1":[[2,2,0]],
            "conc_ratio_max_2":[[1,1,2]]
        }
        max_dia = get_max_cluster_dia_name()
        size_arg = {max_dia:4.05}
        ceBulk = CEBulk( crystalstructure="fcc", a=4.05, size=[4,4,4], basis_elements=[["Al","Mg","Si"]], \
                              conc_args=conc_args, db_name=db_name, max_cluster_size=3, **size_arg)
        ceBulk.reconfigure_settings()
        corr_func = CorrFunction( ceBulk )
        cf = corr_func.get_cf( ceBulk.atoms )
        #prefixes = [name.rpartition("_")[0] for name in cf.keys()]
        #prefixes.remove("")
        eci = {name:1.0 for name in cf.keys()}
        calc = CE( ceBulk, eci )
        n_tests = 10

        # Insert 25 Mg atoms and 25 Si atoms
        n = 18
        for i in range(n):
            calc.calculate( ceBulk.atoms, ["energy"], [(i,"Al","Mg")])
            calc.calculate( ceBulk.atoms, ["energy"], [(i+n,"Al","Si")])
            updated_cf = calc.get_cf()
            brute_force = corr_func.get_cf_by_cluster_names( ceBulk.atoms, updated_cf.keys() )
            for key in updated_cf.keys():
                self.assertAlmostEqual( brute_force[key], updated_cf[key])

        # Swap atoms
        for i in range(n_tests):
            indx1 = np.random.randint(low=0,high=len(ceBulk.atoms))
            symb1 = ceBulk.atoms[indx1].symbol
            indx2 = indx1
            symb2 = symb1
            while( symb2 == symb1 ):
                indx2 = np.random.randint( low=0, high=len(ceBulk.atoms) )
                symb2 = ceBulk.atoms[indx2].symbol
            calc.calculate( ceBulk.atoms, ["energy"], [(indx1,symb1,symb2),(indx2,symb2,symb1)])
            update_cf = calc.get_cf()
            brute_force = corr_func.get_cf_by_cluster_names( ceBulk.atoms, update_cf.keys() )
            for key,value in brute_force.items():
                self.assertAlmostEqual( value, update_cf[key])
Beispiel #2
0
def find_gs_structure(ceBulk, mg_conc):
    fname = "data/{}.json".format(db_name.split(".")[0])
    with open(fname, 'r') as infile:
        ecis = json.load(infile)
    calc = CE(ceBulk, ecis)
    ceBulk.atoms.set_calculator(calc)
    conc = {"Mg": mg_conc, "Al": 1.0 - mg_conc}
    calc.set_composition(conc)
    print(ceBulk.basis_functions)
    formula = ceBulk.atoms.get_chemical_formula()
    temps = [
        800, 700, 500, 300, 200, 100, 50, 20, 19, 18, 15, 14, 13, 12, 11, 10,
        9, 8, 7, 6, 5, 4, 3, 2, 1
    ]
    n_steps_per = 1000
    lowest_struct = mcobs.LowestEnergyStructure(calc, None)
    for T in temps:
        print("Temperature {}".format(T))
        mc_obj = mc.Montecarlo(ceBulk.atoms, T)
        lowest_struct.mc_obj = mc_obj
        mc_obj.attach(lowest_struct)
        mc_obj.runMC(steps=n_steps_per, verbose=False)
        thermo = mc_obj.get_thermodynamic()
        print("Mean energy: {}".format(thermo["energy"]))
    fname = "data/gs_structure%s.xyz" % (formula)
    write(fname, lowest_struct.lowest_energy_atoms)
    print("Lowest energy found: {}".format(lowest_struct.lowest_energy))
    print("GS structure saved to %s" % (fname))
    fname = "data/cf_functions_gs%s.csv" % (formula)
    cf = calc.get_cf()
    with open(fname, 'w') as outfile:
        for key, value in cf.iteritems():
            outfile.write("{},{}\n".format(key, value))
    print("CFs saved to %s" % (fname))
    return lowest_struct.lowest_energy
Beispiel #3
0
    def test_set_singlets( self ):
        if ( not has_ase_with_ce ):
            self.skipTest( "ASE version does not have CE" )
            return

        system_types = [["Al","Mg"],["Al","Mg","Si"],["Al","Mg","Si","Cu"]]

        db_name = "test_singlets.db"
        n_concs = 4
        no_throw = True
        msg = ""
        try:
            for basis_elems in system_types:
                conc_args = {
                    "conc_ratio_min_1":[[1,0]],
                    "conc_ratio_max_1":[[0,1]],
                }
                a = 4.05
                mx_dia_name = get_max_cluster_dia_name()
                size_arg = {mx_dia_name:a}
                ceBulk = CEBulk( crystalstructure="fcc", a=a, size=[5, 5, 5], basis_elements=[basis_elems], conc_args=conc_args, \
                db_name=db_name, max_cluster_size=2,**size_arg)
                ceBulk.reconfigure_settings()
                cf = CorrFunction(ceBulk)
                corrfuncs = cf.get_cf(ceBulk.atoms)
                eci = {name:1.0 for name in corrfuncs.keys()}
                calc = CE( ceBulk,eci )
                for _ in range(n_concs):
                    conc = np.random.rand(len(basis_elems))*0.97
                    conc /= np.sum(conc)
                    conc_dict = {}
                    for i in range(len(basis_elems)):
                        conc_dict[basis_elems[i]] = conc[i]
                    calc.set_composition(conc_dict)
                    ref_cf = calc.get_cf()

                    singlets = {}
                    for key,value in ref_cf.items():
                        if ( key.startswith("c1") ):
                            singlets[key] = value
                    comp = calc.singlet2comp(singlets)
                    dict_comp = "Ref {}. Computed {}".format(conc_dict,comp)
                    for key in comp.keys():
                        self.assertAlmostEqual( comp[key], conc_dict[key], msg=dict_comp, places=1 )
                calc.set_singlets(singlets)
        except Exception as exc:
            msg = str(exc)
            no_throw = False
        self.assertTrue( no_throw, msg=msg )
Beispiel #4
0
 def test_binary_spacegroup( self ):
     if ( not has_ase_with_ce ):
         self.skipTest("ASE version does not have CE")
         return
     bs, db_name = get_bulkspacegroup_binary()
     cf = CorrFunction( bs )
     cf_vals = cf.get_cf( bs.atoms )
     ecis = {name:1.0 for name in cf_vals.keys()}
     calc = CE( bs, ecis )
     bs.atoms.set_calculator( calc )
     for i in range(25):
         if ( bs.atoms[i].symbol == "Al" ):
             new_symb = "Mg"
             old_symb = "Al"
         else:
             new_symb = "Al"
             old_symb = "Mg"
         calc.calculate( bs.atoms, ["energy"], [(i,old_symb,new_symb)] )
         updated_cf = calc.get_cf()
         brute_force = cf.get_cf_by_cluster_names( bs.atoms, updated_cf.keys() )
         for key,value in brute_force.items():
             self.assertAlmostEqual( value, updated_cf[key] )
class PopulationVariance(object):
    """
    Object that estimates the covariance and the mean of all the
    correlation functions in the population
    """
    def __init__(self, BC):
        self.bc = BC
        cf_obj = CorrFunction(self.bc)
        self.init_cf = cf_obj.get_cf(self.bc.atoms)
        ecis = {key: 1.0
                for key in self.init_cf.keys()}  # ECIs do not matter here
        self.calc = CE(self.bc, ecis, initial_cf=self.init_cf)
        self.bc.atoms.set_calculator(self.calc)
        self.elements = self.bc.basis_elements[
            0]  # This should be updated to handle different site types
        self.status_every_sec = 30
        N = len(ecis.keys()) - 1
        self.cov_matrix = np.zeros((N, N))
        self.exp_value = np.zeros(N)

    def swap_random_atoms(self):
        """
        Changes the symbol of a random atom
        """
        indx = np.random.randint(low=0, high=len(self.bc.atoms))
        symb = self.bc.atoms[indx].symbol
        new_symb = self.elements[np.random.randint(low=0,
                                                   high=len(self.elements))]
        system_change = [(indx, symb, new_symb)]
        self.bc.atoms._calc.calculate(self.bc.atoms, ["energy"], system_change)

    def estimate(self, n_probe_structures=10000, fname=""):
        """
        Estimate the covariance matrix
        """

        if (fname != ""):
            if (not fname.endswith(".json")):
                raise ValueError(
                    "The program is going to write a json file so the file extension should be .json"
                )

        step = 0
        cfs = []
        cur_time = time.time()
        while (step < n_probe_structures):
            step += 1
            if (time.time() - cur_time > self.status_every_sec):
                print("Step {} of {}".format(step, n_probe_structures))
                cur_time = time.time()
            for i in range(len(self.bc.atoms)):
                self.swap_random_atoms()
            new_cfs = self.calc.get_cf()
            cf_array = [
                new_cfs[key] for key in self.init_cf.keys() if key != "c0"
            ]  # Make sure that the order is the same as in init_cf
            self.update_cov_matrix(cf_array)

        cfs = np.array(cfs)
        cov = self.cov_matrix / n_probe_structures
        mu = self.exp_value / n_probe_structures
        cov -= np.outer(mu, mu)
        return cov, mu

    def array2dict(self, cov, mu):
        """
        Converts an array to a dictionary
        """
        # Create dictionaries
        keys = self.init_cf.keys()
        del keys[keys.index("c0")]
        mu_dict = {keys[i]: mu[i] for i in range(len(keys))}

        cov_dict = {key: {} for key in keys}
        for i in range(len(keys)):
            for j in range(len(keys)):
                cov_dict[keys[i]][keys[j]] = cov[i, j]
        return cov_dict, mu_dict

    def update_cov_matrix(self, new_cfs):
        """
        Updates the covariance matrix
        """
        outer = np.outer(new_cfs, new_cfs)
        self.cov_matrix += outer
        self.exp_value += np.array(new_cfs)

    def save(self, eigval, eigvec, fname="eigenvectors.h5", fraction=0.95):
        """
        Store the lowest fraction of the eigenvectors
        """
        srt_indx = np.argsort(eigval)[::-1]
        eigval_srt = [eigval[indx] for indx in srt_indx]
        eigvec_srt = np.array([eigvec[:, indx] for indx in srt_indx]).T
        cumsum_eig = np.cumsum(eigval_srt)
        tot_sum = np.sum(eigval_srt)

        relative_sum = cumsum_eig / tot_sum

        max_indx = np.argmin(np.abs(relative_sum - fraction))
        matrix = eigvec_srt[:, :max_indx]
        eigen = eigval_srt[:max_indx]
        with h5.File(fname, 'w') as hf:
            dset_vec = hf.create_dataset("eigenvectors", data=matrix)
            dset_eigen = hf.create_dataset("eigenvalues", data=eigen)
            dset_eigen.attrs["fraction"] = fraction

        print("Result written to {}".format(fname))

    def diagonalize(self, cov, plot=False):
        """
        Diagonalize the covariance matrix
        """
        eigval, eigvec = np.linalg.eigh(cov)

        # Sort accorting to eigenvalues
        srt_indx = np.argsort(eigval)[::-1]
        eigval_srt = [eigval[indx] for indx in srt_indx]
        eigvec_srt = np.array([eigvec[:, indx] for indx in srt_indx]).T

        cumsum_eig = np.cumsum(eigval_srt)
        tot_sum = np.sum(eigval_srt)

        if (plot):
            x_val = np.arange(len(eigval))
            fig = plt.figure()
            ax = fig.add_subplot(1, 1, 1)
            ax.plot(x_val, cumsum_eig / tot_sum, ls="steps")
            ax.set_xlabel("Number of eigenvectors")
            ax.set_ylabel("Normalized variance")
        return eigval, eigvec

    def plot_eigen(self, eigenvalues, eigenvectors):
        """
        Creates a visualization of the eigenvectors and the eigenvalues
        NOTE: Eigenvalues and eigenvectors must NOT be sorted. They have
              to be given in the same order as returned by diagonalize
        """
        keys = self.init_cf.keys()
        del keys[keys.index("c0")]
        srt_indx = np.argsort(eigenvalues)[::-1]
        key_srt = [keys[indx] for indx in srt_indx]
        eigval_srt = [eigenvalues[indx] for indx in srt_indx]
        eigvec_srt = np.array([eigenvectors[:, indx] for indx in srt_indx]).T

        grid_kw = {"hspace": 0.0, "height_ratios": [1, 4]}
        fig, ax = plt.subplots(nrows=2, sharex=True, gridspec_kw=grid_kw)
        x = np.arange(len(eigvec_srt))
        cumsum = np.cumsum(eigval_srt)
        tot_sum = np.sum(eigval_srt)
        ax[0].plot(x, cumsum / tot_sum, ls="steps")
        keys_srt, eigvec_srt = self.sort_eigenvectors_by_size(keys, eigvec_srt)
        #ax[1].imshow( eigvec_srt, cmap="coolwarm", aspect="auto" )
        print(eigvec_srt[:, 0])

        # Separation lines to separate different sizes
        hlines = []
        size = 2
        for i, name in enumerate(keys_srt):
            prefix = "c{}".format(size)
            if (name.startswith(prefix)):
                hlines.append(i)
                size += 1

        for line in hlines:
            ax[1].axhline(line)
        return fig

    def sort_eigenvectors_by_size(self, keys, eigvec):
        """
        Sort the eigenvector values
        """
        srt_indx = np.argsort(keys)
        keys_srt = [keys[indx] for indx in srt_indx]
        eigvec_srt = np.array([eigvec[indx, :] for indx in srt_indx])
        return keys_srt, eigvec_srt
Beispiel #6
0
def thermodynamic_integration(phase):
    alat = 3.8
    conc_args = {}
    conc_args['conc_ratio_min_1'] = [[1, 0]]
    conc_args['conc_ratio_max_1'] = [[0, 1]]
    kwargs = {
        "crystalstructure": 'fcc',
        "a": 3.8,
        "size": [10, 10, 10],
        "basis_elements": [['Cu', 'Au']],
        "conc_args": conc_args,
        "db_name": 'temp_sgc.db',
        "max_cluster_size": 3,
        "max_cluster_dist": 1.5 * alat
    }
    bc1 = BulkCrystal(**kwargs)
    bf = bc1._get_basis_functions()[0]

    with open("data/eci_aucu.json", 'r') as infile:
        eci = json.load(infile)

    db = dataset.connect("sqlite:///{}".format(canonical_db))
    tbl = db["corrfunc"]
    if phase == "Au" or phase == "Cu":
        atoms1 = bc1.atoms
        for atom in atoms1:
            atom.symbol = phase
        cf1 = get_pure_cf(eci, bf[phase])
    else:
        atoms = read(phase)
        row = tbl.find_one(runID=gs[phase])
        row.pop("id")
        row.pop("runID")
        cf1 = row
    # TODO: Fix this when running with a pure phase
    symbs = [atom.symbol for atom in atoms]

    cf1 = get_pure_cf(eci, bf[bc1.atoms[0].symbol])
    atoms = bc1.atoms
    calc = CE(bc1, eci=eci, initial_cf=cf1)
    calc.set_symbols(symbs)
    atoms.set_calculator(calc)

    sgc_db = dataset.connect("sqlite:///{}".format(sgc_db_name))
    tbl = sgc_db["results"]
    tbl_cf = sgc_db["corr_func"]
    mu = 0.223
    nsteps = 100 * len(atoms)
    equil_param = {"mode": "fixed", "maxiter": 10 * len(atoms)}
    order_param = SiteOrderParameter(atoms)
    T = np.linspace(100, 600, 40)
    # mu = np.linspace(0.223, 0.19, 20).tolist()
    mu = [0.223]
    for temp in T:
        for m in mu:
            chemical_potential = {"c1_0": m}
            # mc = SGCMonteCarlo(atoms, temp, mpicomm=comm, symbols=["Au", "Cu"])
            mc = Montecarlo(atoms, temp)
            mc.attach(order_param)
            init_formula = atoms.get_chemical_formula()
            # mc.runMC(steps=nsteps, equil_params=equil_param,
            #          chem_potential=chemical_potential)
            mc.runMC(steps=nsteps, equil_params=equil_param)
            # thermo = mc.get_thermodynamic(reset_ecis=True)
            thermo = mc.get_thermodynamic()
            thermo["init_formula"] = init_formula
            thermo["final_formula"] = atoms.get_chemical_formula()
            avg, std = order_param.get_average()
            thermo["order_avg"] = avg
            thermo["order_std"] = std
            thermo["valid"] = True
            thermo["integration_path"] = "NN"
            if rank == 0:
                uid = tbl.insert(thermo)
                cf = calc.get_cf()
                cf["runID"] = uid
                tbl_cf.insert(cf)