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])
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
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 )
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
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)