def __init__(self, *args, **kwargs): super(TestGroundStateFinderInactiveSublatticeSameSpecies, self).__init__(*args, **kwargs) self.chemical_symbols = [['Ag', 'Au'], ['Ag']] self.cutoffs = [4.3] a = 4.0 structure_prim = bulk(self.chemical_symbols[0][1], a=a) structure_prim.append( Atom(self.chemical_symbols[1][0], position=(a / 2, a / 2, a / 2))) self.structure_prim = structure_prim self.cs = ClusterSpace(self.structure_prim, self.cutoffs, self.chemical_symbols) self.ce = ClusterExpansion(self.cs, [0, 0, 0.1, -0.02]) self.all_possible_structures = [] self.supercell = self.structure_prim.repeat(2) sublattices = self.cs.get_sublattices(self.supercell) self.n_active_sites = [ len(subl.indices) for subl in sublattices.active_sublattices ] for i, sym in enumerate(self.supercell.get_chemical_symbols()): if sym not in self.chemical_symbols[0]: continue structure = self.supercell.copy() structure.symbols[i] = self.chemical_symbols[0][0] self.all_possible_structures.append(structure)
def __init__(self, *args, **kwargs): super(TestGroundStateFinderZeroParameter, self).__init__(*args, **kwargs) self.chemical_symbols = ['Ag', 'Au'] self.cutoffs = [4.3] self.structure_prim = bulk(self.chemical_symbols[1], a=4.0) self.cs = ClusterSpace(self.structure_prim, self.cutoffs, self.chemical_symbols) nonzero_ce = ClusterExpansion(self.cs, [0, 0, 0.1, -0.02]) lolg = LocalOrbitListGenerator( self.cs.orbit_list, Structure.from_atoms(self.structure_prim), self.cs.fractional_position_tolerance) full_orbit_list = lolg.generate_full_orbit_list() binary_parameters_zero = transform_parameters(self.structure_prim, full_orbit_list, nonzero_ce.parameters) binary_parameters_zero[1] = 0 A = get_transformation_matrix(self.structure_prim, full_orbit_list) Ainv = np.linalg.inv(A) zero_parameters = np.dot(Ainv, binary_parameters_zero) self.ce = ClusterExpansion(self.cs, zero_parameters) self.all_possible_structures = [] self.supercell = self.structure_prim.repeat(2) for i in range(len(self.supercell)): structure = self.supercell.copy() structure.symbols[i] = self.chemical_symbols[0] self.all_possible_structures.append(structure)
def __init__(self, *args, **kwargs): super(TestGroundStateFinderTwoActiveSublattices, self).__init__(*args, **kwargs) a = 4.0 self.chemical_symbols = [['Au', 'Pd'], ['Li', 'Na']] self.cutoffs = [3.0] structure_prim = bulk(self.chemical_symbols[0][0], a=a) structure_prim.append( Atom(self.chemical_symbols[1][0], position=(a / 2, a / 2, a / 2))) structure_prim.wrap() self.structure_prim = structure_prim self.cs = ClusterSpace(self.structure_prim, self.cutoffs, self.chemical_symbols) parameters = [0.1, -0.45, 0.333, 2, -1.42, 0.98] self.ce = ClusterExpansion(self.cs, parameters) self.all_possible_structures = [] self.supercell = self.structure_prim.repeat(2) self.sl1_indices = [ s for s, sym in enumerate(self.supercell.get_chemical_symbols()) if sym == self.chemical_symbols[0][0] ] self.sl2_indices = [ s for s, sym in enumerate(self.supercell.get_chemical_symbols()) if sym == self.chemical_symbols[1][0] ] for i in self.sl1_indices: for j in self.sl2_indices: structure = self.supercell.copy() structure.symbols[i] = self.chemical_symbols[0][1] structure.symbols[j] = self.chemical_symbols[1][1] self.all_possible_structures.append(structure)
def __init__(self, *args, **kwargs): super(TestGroundStateFinder, self).__init__(*args, **kwargs) self.chemical_symbols = ['Ag', 'Au'] self.cutoffs = [4.3] self.structure_prim = bulk(self.chemical_symbols[1], a=4.0) self.cs = ClusterSpace(self.structure_prim, self.cutoffs, self.chemical_symbols) self.ce = ClusterExpansion(self.cs, [0, 0, 0.1, -0.02]) self.all_possible_structures = [] self.supercell = self.structure_prim.repeat(2) for i in range(len(self.supercell)): structure = self.supercell.copy() structure.symbols[i] = self.chemical_symbols[0] self.all_possible_structures.append(structure)
def test_sublattice_probabilities(self): """ Tests the sublattice_probabilities keyword argument. """ # setup system with inactive sublattice prim = bulk('W', 'bcc', cubic=True) prim[1].symbol = 'C' chemical_symbols = [['W', 'Ti'], ['C', 'N']] cs = ClusterSpace(prim, cutoffs=[0], chemical_symbols=chemical_symbols) ce = ClusterExpansion(cs, [1] * len(cs)) structure = prim.repeat(2) structure[0].symbol = 'Ti' structure[1].symbol = 'N' calculator = ClusterExpansionCalculator(structure, ce) # test default ensemble = WangLandauEnsemble(structure, calculator, energy_spacing=1) probs = ensemble._get_swap_sublattice_probabilities() self.assertEqual(len(probs), 2) self.assertAlmostEqual(probs[0], 0.5) self.assertAlmostEqual(probs[1], 0.5) # test override ensemble = WangLandauEnsemble(structure, calculator, energy_spacing=1, sublattice_probabilities=[0.2, 0.8]) probs = ensemble._sublattice_probabilities self.assertEqual(len(probs), 2) self.assertAlmostEqual(probs[0], 0.2) self.assertAlmostEqual(probs[1], 0.8)
def __init__(self, *args, **kwargs): super(TestEnsembleSpectatorSublattice, self).__init__(*args, **kwargs) lattice_parameter = 4.0 prim = bulk('Pd', a=lattice_parameter, crystalstructure='fcc') prim.append(Atom('H', position=(lattice_parameter / 2,)*3)) self.structure = prim.repeat(3) for i, atom in enumerate(self.structure): if i % 3 == 0: if atom.symbol == 'Pd': continue else: atom.symbol = 'V' cutoffs = [5, 5, 4] elements = [['Pd'], ['H', 'V']] self.chemical_potentials = {'H': 5, 'V': 0} self.phis = {'H': -1.0} self.kappa = 200.0 self.ensemble_specs = [{'ensemble': 'canonical', 'sublattice_index': 0}, {'ensemble': 'semi-grand', 'sublattice_index': 0, 'chemical_potentials': self.chemical_potentials}, {'ensemble': 'vcsgc', 'sublattice_index': 0, 'phis': self.phis, 'kappa': self.kappa}] self.cs = ClusterSpace(prim, cutoffs, elements) parameters = parameters = np.array([1.2] * len(self.cs)) self.ce = ClusterExpansion(self.cs, parameters) self.temperature = 100.0
def __init__(self, *args, **kwargs): super(TestEnsemble, self).__init__(*args, **kwargs) # prepare cluster expansion self.prim = Atoms('Au', positions=[[0, 0, 0]], cell=[1, 1, 10], pbc=True) cs = ClusterSpace(self.prim, cutoffs=[1.1], chemical_symbols=['Ag', 'Au']) self.ce = ClusterExpansion(cs, [0, 0, 2]) # prepare initial configuration self.structure = self.prim.repeat((2, 2, 1)) self.structure[0].symbol = 'Ag' self.structure[1].symbol = 'Ag' self.structure = self.structure.repeat((2, 2, 1)) # other variables and parameters self.trial_move = 'swap' self.energy_spacing = 1 self.flatness_limit = 0.8 self.fill_factor_limit = 1e-4 self.flatness_check_interval = 10 self.data_container_write_period = 499 self.ensemble_data_write_interval = 1 self.trajectory_write_interval = 10
def test_restart_with_inactive_sites(self): """ Tests restart works with inactive sites """ chemical_symbols = [['C', 'Be'], ['W']] prim = bulk( 'W', 'bcc', cubic=True, ) cs = ClusterSpace(structure=prim, chemical_symbols=chemical_symbols, cutoffs=[5]) parameters = [1] * len(cs) ce = ClusterExpansion(cs, parameters) size = 4 structure = ce._cluster_space.primitive_structure.repeat(size) calculator = ClusterExpansionCalculator(structure, ce) # Carry out Monte Carlo simulations dc_file = tempfile.NamedTemporaryFile() mc = ConcreteEnsemble(structure=structure, calculator=calculator) mc.write_data_container(dc_file.name) mc.run(10) # and now restart mc = ConcreteEnsemble(structure=structure, calculator=calculator, dc_filename=dc_file.name) mc.run(10)
def test_get_swap_sublattice_probabilities(self): """ Tests the get_swap_sublattice_probabilities function. """ # setup system with inactive sublattice prim = bulk('Al').repeat([2, 1, 1]) chemical_symbols = [['Al'], ['Ag', 'Al']] cs = ClusterSpace(prim, cutoffs=[0], chemical_symbols=chemical_symbols) ce = ClusterExpansion(cs, [1] * len(cs)) supercell = prim.repeat(2) supercell[1].symbol = 'Ag' ce_calc = ClusterExpansionCalculator(supercell, ce) ensemble = CanonicalEnsemble(supercell, ce_calc, temperature=100) # test get_swap_sublattice_probabilities probs = ensemble._get_swap_sublattice_probabilities() self.assertEqual(len(probs), 2) self.assertEqual(probs[0], 1) self.assertEqual(probs[1], 0) # test raise when swap not possible on either lattice supercell[1].symbol = 'Al' ce_calc = ClusterExpansionCalculator(supercell, ce) with self.assertRaises(ValueError) as context: ensemble = CanonicalEnsemble(supercell, ce_calc, temperature=100) self.assertIn('No canonical swaps are possible on any of the', str(context.exception))
def test_read_write(self): """Tests read and write functionalities.""" # save to file temp_file = tempfile.NamedTemporaryFile() self.ce.write(temp_file.name) # read from file temp_file.seek(0) ce_read = ClusterExpansion.read(temp_file.name) # check cluster space self.assertEqual(self.cs._input_structure, ce_read._cluster_space._input_structure) self.assertEqual(self.cs._cutoffs, ce_read._cluster_space._cutoffs) self.assertEqual(self.cs._input_chemical_symbols, ce_read._cluster_space._input_chemical_symbols) # check parameters self.assertIsInstance(ce_read.parameters, np.ndarray) self.assertEqual(list(ce_read.parameters), list(self.parameters)) # check metadata self.assertEqual(len(self.ce.metadata), len(ce_read.metadata)) self.assertSequenceEqual(sorted(self.ce.metadata.keys()), sorted(ce_read.metadata.keys())) for key in self.ce.metadata.keys(): self.assertEqual(self.ce.metadata[key], ce_read.metadata[key])
def __init__(self, *args, **kwargs): super(TestEnsemble, self).__init__(*args, **kwargs) prim = Atoms('Au', positions=[[0, 0, 0]], cell=[1, 1, 1], pbc=True) self.structure = prim.repeat(3) self.cs = ClusterSpace(prim, cutoffs=[1.1], chemical_symbols=['Ag', 'Au']) self.ce = ClusterExpansion(self.cs, [0, 0, 2])
def test_init(self): """Tests that initialization works.""" self.assertIsInstance(self.ce, ClusterExpansion) # test whether method raises Exception with self.assertRaises(ValueError) as context: ClusterExpansion(self.cs, [0.0]) self.assertTrue('cluster_space (5) and parameters (1) must have the' ' same length' in str(context.exception))
def __init__(self, *args, **kwargs): super(TestCECalculatorTernaryHCP, self).__init__(*args, **kwargs) self.structure = bulk('Al', 'hcp', a=4.0, c=3.1) self.cutoffs = [6, 6, 6] self.subelements = ['Al', 'Ge', 'H'] self.cs = ClusterSpace(self.structure, self.cutoffs, self.subelements) params_len = len(self.cs) params = [1.0] * params_len self.ce = ClusterExpansion(self.cs, params)
def __init__(self, *args, **kwargs): super(TestCECalculatorBinaryBCC, self).__init__(*args, **kwargs) self.structure = bulk('Al', 'bcc', a=4.0) self.cutoffs = [6, 6, 6] self.subelements = ['Al', 'Ge'] self.cs = ClusterSpace(self.structure, self.cutoffs, self.subelements) params_len = len(self.cs) params = [1.1] * params_len self.ce = ClusterExpansion(self.cs, params)
def __init__(self, *args, **kwargs): super(TestCEObserver, self).__init__(*args, **kwargs) self.structure = bulk('Al').repeat(3) cutoffs = [6, 6, 5] subelements = ['Al', 'Ge'] cs = ClusterSpace(self.structure, cutoffs, subelements) params_len = len(cs) params = list(range(params_len)) self.ce = ClusterExpansion(cs, params)
def __init__(self, *args, **kwargs): super(TestGroundStateFinderTriplets, self).__init__(*args, **kwargs) self.chemical_symbols = ['Au', 'Pd'] self.cutoffs = [3.0, 3.0] structure_prim = fcc111(self.chemical_symbols[0], a=4.0, size=(1, 1, 6), vacuum=10, periodic=True) structure_prim.wrap() self.structure_prim = structure_prim self.cs = ClusterSpace(self.structure_prim, self.cutoffs, self.chemical_symbols) parameters = [0.0] * 4 + [0.1] * 6 + [-0.02] * 11 self.ce = ClusterExpansion(self.cs, parameters) self.all_possible_structures = [] self.supercell = self.structure_prim.repeat((2, 2, 1)) for i in range(len(self.supercell)): structure = self.supercell.copy() structure.symbols[i] = self.chemical_symbols[1] self.all_possible_structures.append(structure)
def __init__(self, *args, **kwargs): super(TestEnsemble, self).__init__(*args, **kwargs) self.structure = bulk('Al').repeat(3) for i, atom in enumerate(self.structure): if i % 2 == 0: atom.symbol = 'Ga' cutoffs = [5, 5, 4] elements = ['Al', 'Ga'] self.cs = ClusterSpace(self.structure, cutoffs, elements) parameters = parameters = np.array([1.2] * len(self.cs)) self.ce = ClusterExpansion(self.cs, parameters) self.temperature = 100.0
def test_init_fails_for_faulty_chemical_symbols(self): """Tests that initialization fails if species exists on mutliple sublattices""" structure = bulk('Al').repeat(2) cutoffs = [4.0] elements = [['Al', 'Ga']] * 4 + [['Al', 'Ge']] * 4 cs = ClusterSpace(structure, cutoffs, elements) ce = ClusterExpansion(cs, np.arange(0, len(cs))) calc = ClusterExpansionCalculator(structure, ce) with self.assertRaises(ValueError) as context: ConcreteEnsemble(structure, calc) self.assertIn('found on multiple active sublattices', str(context.exception))
def test_init_fails_for_ternary_with_one_active_sublattice(self): """Tests that initialization fails for a ternary system with one active sublattice.""" chemical_symbols = ['Au', 'Ag', 'Pd'] cs = ClusterSpace(self.structure_prim, cutoffs=self.cutoffs, chemical_symbols=chemical_symbols) ce = ClusterExpansion(cs, [0.0] * len(cs)) with self.assertRaises(NotImplementedError) as cm: icet.tools.ground_state_finder.GroundStateFinder(ce, self.supercell, verbose=False) self.assertTrue( 'Currently, systems with more than two allowed species on any sublattice ' 'are not supported.' in str(cm.exception))
def test_property_metadata(self): """ Test metadata property. """ user_metadata = dict(parameters=[1, 2, 3], fit_method='ardr') ce = ClusterExpansion(self.cs, self.parameters, metadata=user_metadata) metadata = ce.metadata # check for user metadata self.assertIn('parameters', metadata.keys()) self.assertIn('fit_method', metadata.keys()) # check for default metadata self.assertIn('date_created', metadata.keys()) self.assertIn('username', metadata.keys()) self.assertIn('hostname', metadata.keys()) self.assertIn('icet_version', metadata.keys())
def test_mc_with_one_filled_sublattice(self): """ Tests if WL simulation works with two sublattices where one sublattice is filled/empty. """ # setup two sublattices prim = bulk('W', crystalstructure='bcc', a=1.0, cubic=True) cs = ClusterSpace(prim, [1.5], [['W', 'Ti'], ['C', 'Be']]) ce = ClusterExpansion(cs, [1] * len(cs)) # setup supercell with one filled sublattice structure = prim.copy() structure[1].symbol = 'C' structure = structure.repeat(4) structure[2].symbol = 'Ti' # run mc calculator = ClusterExpansionCalculator(structure, ce) mc = WangLandauEnsemble(structure, calculator, energy_spacing=1) mc.run(50)
def __init__(self, *args, **kwargs): super(TestEnsemble, self).__init__(*args, **kwargs) # setup supercell self.structure = bulk('Al').repeat(3) for i, atom in enumerate(self.structure): if i % 2 == 0: atom.symbol = 'Ga' # setup cluster expansion cutoffs = [5, 5, 4] elements = ['Al', 'Ga'] cs = ClusterSpace(self.structure, cutoffs, elements) parameters = parameters = np.array([1.2] * len(cs)) self.ce = ClusterExpansion(cs, parameters) self.T_start = 1000.0 self.T_stop = 0.0 self.n_steps = 500
def test_read_write_pruned(self): """Tests read and write functionalities.""" # save to file temp_file = tempfile.NamedTemporaryFile() self.ce.prune(indices=[2, 3]) self.ce.prune(tol=3) pruned_params = self.ce.parameters pruned_cs_len = len(self.ce._cluster_space) self.ce.write(temp_file.name) # read from file temp_file.seek(0) ce_read = ClusterExpansion.read(temp_file.name) params_read = ce_read.parameters cs_len_read = len(ce_read._cluster_space) # check cluster space self.assertEqual(cs_len_read, pruned_cs_len) self.assertEqual(list(params_read), list(pruned_params))
def print_timing_ratios(structure, local_iters, total_iters, sizes, cutoffs): """ Prints timing ratios between local and total energy calculations. """ print( '# 1:size 2:local_iters 3:total_iters 4:atom size, 5:ce calc init time (sec)' ', 6:t_local 7:t_total 8:t_total/t_local') cs = ClusterSpace(structure, cutoffs, chemical_symbols=['Al', 'Ga']) parameters = np.array([1.2 for _ in range(len(cs))]) ce = ClusterExpansion(cs, parameters) for size in sizes: structure_cpy = structure.repeat(size) occupations = structure_cpy.get_atomic_numbers() t0 = time.time() calculator = ClusterExpansionCalculator(structure_cpy, ce) time_ce_init = time.time() - t0 t_local = time_local_energy(calculator, occupations, local_iters) t_total = time_total_energy(calculator, occupations, total_iters) print(size, local_iters, total_iters, len(structure_cpy), time_ce_init, t_local, t_total, t_total / t_local)
def test_mc_with_one_filled_sublattice(self): """ Tests if canonical ensemble works with two sublattices where one sublattice is filled/empty. """ # setup two sublattices prim = bulk('W', 'bcc', a=3.0, cubic=True) cs = ClusterSpace(prim, [4.0], [['W', 'Ti'], ['C', 'Be']]) ce = ClusterExpansion(cs, np.arange(0, len(cs))) # setup supercell with one filled sublattice supercell = prim.copy() supercell[1].symbol = 'C' supercell = supercell.repeat(4) supercell[2].symbol = 'Ti' # run mc calc = ClusterExpansionCalculator(supercell, ce) mc = CanonicalEnsemble(supercell, calc, 300) mc.run(50)
def __init__(self, *args, **kwargs): super(TestEnsembleSublattices, self).__init__(*args, **kwargs) lattice_parameter = 4.0 prim = bulk('Pd', a=lattice_parameter, crystalstructure='fcc') prim.append(Atom('H', position=(lattice_parameter / 2, ) * 3)) self.structure = prim.repeat(3) for i, atom in enumerate(self.structure): if i % 3 == 0: if atom.symbol == 'Pd': atom.symbol = 'Au' else: atom.symbol = 'V' cutoffs = [5, 5, 4] elements = [['Pd', 'Au'], ['H', 'V']] self.phis = {'Au': -1.3, 'H': -1.0} self.kappa = 200.0 self.cs = ClusterSpace(prim, cutoffs, elements) parameters = parameters = np.array([1.2] * len(self.cs)) self.ce = ClusterExpansion(self.cs, parameters) self.temperature = 100.0
def __init__(self, *args, **kwargs): super(TestEnsemble, self).__init__(*args, **kwargs) self.structure = bulk('Al').repeat(3) for i, atom in enumerate(self.structure): if i % 2 == 0: atom.symbol = 'Ga' cutoffs = [5, 5, 4] elements = ['Al', 'Ga'] self.chemical_potentials = {'Al': 5, 'Ga': 0} self.phis = {'Al': -1.3} self.kappa = 10.0 self.ensemble_specs = [{'ensemble': 'canonical', 'sublattice_index': 0}, {'ensemble': 'semi-grand', 'sublattice_index': 0, 'chemical_potentials': self.chemical_potentials}, {'ensemble': 'vcsgc', 'sublattice_index': 0, 'phis': self.phis, 'kappa': self.kappa}] self.cs = ClusterSpace(self.structure, cutoffs, elements) parameters = parameters = np.array([1.2] * len(self.cs)) self.ce = ClusterExpansion(self.cs, parameters) self.temperature = 100.0
def test_get_sublattice_probabilities(self): """ Tests the get_swap/flip_sublattice_probabilities function. """ # setup system with inactive sublattice prim = bulk('Al').repeat([2, 1, 1]) chemical_symbols = [['Al'], ['Ag', 'Al']] cs = ClusterSpace(prim, cutoffs=[0], chemical_symbols=chemical_symbols) ce = ClusterExpansion(cs, [1] * len(cs)) structure = prim.repeat(2) structure[1].symbol = 'Ag' calculator = ClusterExpansionCalculator(structure, ce) ensemble = WangLandauEnsemble(structure, calculator, energy_spacing=1) # test get_swap_sublattice_probabilities probs = ensemble._get_swap_sublattice_probabilities() self.assertEqual(len(probs), 2) self.assertEqual(probs[0], 1) self.assertEqual(probs[1], 0) # test get_flip_sublattice_probabilities probs = ensemble._get_flip_sublattice_probabilities() self.assertEqual(len(probs), 2) self.assertEqual(probs[0], 1) self.assertEqual(probs[1], 0) # test raise when swap not possible on either lattice structure[1].symbol = 'Al' calculator = ClusterExpansionCalculator(structure, ce) with self.assertRaises(ValueError) as context: ensemble = WangLandauEnsemble(structure, calculator, energy_spacing=1) self.assertIn('No swaps are possible on any of the', str(context.exception))
# This scripts runs in about 6 seconds on an i7-6700K CPU. import matplotlib.pyplot as plt from ase.db import connect from icet import ClusterExpansion # step 1: Compile predicted and reference data for plotting ce = ClusterExpansion.read('mixing_energy.ce') data = {'concentration': [], 'reference_energy': [], 'predicted_energy': []} db = connect('reference_data.db') for row in db.select('natoms<=6'): data['concentration'].append(row.concentration) # the factor of 1e3 serves to convert from eV/atom to meV/atom data['reference_energy'].append(1e3 * row.mixing_energy) data['predicted_energy'].append(1e3 * ce.predict(row.toatoms())) # step 2: Plot results fig, ax = plt.subplots(figsize=(4, 3)) ax.set_xlabel(r'Pd concentration') ax.set_ylabel(r'Mixing energy (meV/atom)') ax.set_xlim([0, 1]) ax.set_ylim([-69, 15]) ax.scatter(data['concentration'], data['reference_energy'], marker='o', label='reference') ax.scatter(data['concentration'], data['predicted_energy'], marker='x', label='CE prediction') plt.savefig('mixing_energy_comparison.png', bbox_inches='tight')
class TestGroundStateFinderTwoActiveSublattices(unittest.TestCase): """Container for test of the class functionality for a system with two active sublattices.""" def __init__(self, *args, **kwargs): super(TestGroundStateFinderTwoActiveSublattices, self).__init__(*args, **kwargs) a = 4.0 self.chemical_symbols = [['Au', 'Pd'], ['Li', 'Na']] self.cutoffs = [3.0] structure_prim = bulk(self.chemical_symbols[0][0], a=a) structure_prim.append( Atom(self.chemical_symbols[1][0], position=(a / 2, a / 2, a / 2))) structure_prim.wrap() self.structure_prim = structure_prim self.cs = ClusterSpace(self.structure_prim, self.cutoffs, self.chemical_symbols) parameters = [0.1, -0.45, 0.333, 2, -1.42, 0.98] self.ce = ClusterExpansion(self.cs, parameters) self.all_possible_structures = [] self.supercell = self.structure_prim.repeat(2) self.sl1_indices = [ s for s, sym in enumerate(self.supercell.get_chemical_symbols()) if sym == self.chemical_symbols[0][0] ] self.sl2_indices = [ s for s, sym in enumerate(self.supercell.get_chemical_symbols()) if sym == self.chemical_symbols[1][0] ] for i in self.sl1_indices: for j in self.sl2_indices: structure = self.supercell.copy() structure.symbols[i] = self.chemical_symbols[0][1] structure.symbols[j] = self.chemical_symbols[1][1] self.all_possible_structures.append(structure) def shortDescription(self): """Silences unittest from printing the docstrings in test cases.""" return None def setUp(self): """Setup before each test.""" self.gsf = icet.tools.ground_state_finder.GroundStateFinder( self.ce, self.supercell, verbose=False) def test_init(self): """Tests that initialization of tested class work.""" # initialize from ClusterExpansion instance gsf = icet.tools.ground_state_finder.GroundStateFinder(self.ce, self.supercell, verbose=False) self.assertIsInstance(gsf, icet.tools.ground_state_finder.GroundStateFinder) def test_get_ground_state(self): """Tests get_ground_state functionality.""" target_val = min([ self.ce.predict(structure) for structure in self.all_possible_structures ]) # Provide counts for the first/first species species_count = { self.chemical_symbols[0][0]: len(self.sl1_indices) - 1, self.chemical_symbols[1][0]: len(self.sl2_indices) - 1 } ground_state = self.gsf.get_ground_state(species_count=species_count) predicted_species00 = self.ce.predict(ground_state) self.assertEqual(predicted_species00, target_val) # Provide counts for the first/second species species_count = { self.chemical_symbols[0][0]: len(self.sl1_indices) - 1, self.chemical_symbols[1][1]: 1 } ground_state = self.gsf.get_ground_state(species_count=species_count) predicted_species01 = self.ce.predict(ground_state) self.assertEqual(predicted_species01, predicted_species00) # Provide counts for second/second species species_count = { self.chemical_symbols[0][1]: 1, self.chemical_symbols[1][1]: 1 } ground_state = self.gsf.get_ground_state(species_count=species_count) predicted_species11 = self.ce.predict(ground_state) self.assertEqual(predicted_species11, predicted_species01) def _test_ground_state_cluster_vectors_in_database(self, db_name): """Tests get_ground_state functionality by comparing the cluster vectors for the structures in the databases.""" filename = inspect.getframeinfo(inspect.currentframe()).filename path = os.path.dirname(os.path.abspath(filename)) db = db_connect(os.path.join(path, db_name)) # Select the structure set with the lowest pairwise correlations selections = ['id={}'.format(i) for i in [7, 13, 15, 62, 76]] for selection in selections: row = db.get(selection) structure = row.toatoms() target_cluster_vector = self.cs.get_cluster_vector(structure) species_count = { self.chemical_symbols[0][0]: structure.get_chemical_symbols().count( self.chemical_symbols[0][0]), self.chemical_symbols[1][0]: structure.get_chemical_symbols().count( self.chemical_symbols[1][0]) } ground_state = self.gsf.get_ground_state( species_count=species_count) gs_cluster_vector = self.cs.get_cluster_vector(ground_state) mean_diff = np.mean(abs(target_cluster_vector - gs_cluster_vector)) self.assertLess(mean_diff, 1e-8) def test_ground_state_cluster_vectors(self): """Tests get_ground_state functionality by comparing the cluster vectors for ground states obtained from simulated annealing.""" self._test_ground_state_cluster_vectors_in_database( '../../../structure_databases/annealing_ground_states.db') def test_get_ground_state_fails_for_faulty_species_to_count(self): """Tests that get_ground_state fails if species_to_count is faulty.""" # Check that get_ground_state fails if counts are provided for a both species on one # of the active sublattices species_count = { self.chemical_symbols[0][0]: len(self.sl1_indices) - 1, self.chemical_symbols[0][1]: 1, self.chemical_symbols[1][1]: 1 } with self.assertRaises(ValueError) as cm: self.gsf.get_ground_state(species_count=species_count) self.assertTrue( 'Provide counts for at most one of the species on each active sublattice ' '({}), not {}!'.format(self.gsf._active_species, list(species_count.keys())) in str( cm.exception)) # Check that get_ground_state fails if the count exceeds the number sites on the first # sublattice faulty_species = self.chemical_symbols[0][1] faulty_count = len(self.supercell) species_count = { faulty_species: faulty_count, self.chemical_symbols[1][1]: 1 } n_active_sites = len([ sym for sym in self.supercell.get_chemical_symbols() if sym == self.chemical_symbols[0][0] ]) with self.assertRaises(ValueError) as cm: self.gsf.get_ground_state(species_count=species_count) self.assertTrue( 'The count for species {} ({}) must be a positive integer and cannot ' 'exceed the number of sites on the active sublattice ' '({})'.format(faulty_species, faulty_count, n_active_sites) in str( cm.exception)) # Check that get_ground_state fails if the count exceeds the number sites on the second # sublattice faulty_species = self.chemical_symbols[1][1] faulty_count = len(self.supercell) species_count = { faulty_species: faulty_count, self.chemical_symbols[0][1]: 1 } n_active_sites = len([ sym for sym in self.supercell.get_chemical_symbols() if sym == self.chemical_symbols[1][0] ]) with self.assertRaises(ValueError) as cm: self.gsf.get_ground_state(species_count=species_count) self.assertTrue( 'The count for species {} ({}) must be a positive integer and cannot ' 'exceed the number of sites on the active sublattice ' '({})'.format(faulty_species, faulty_count, n_active_sites) in str( cm.exception)) def test_get_ground_state_passes_for_partial_species_to_count(self): # Check that get_ground_state passes if a single count is provided species_count = {self.chemical_symbols[0][1]: 1} self.gsf.get_ground_state(species_count=species_count) # Check that get_ground_state passes no counts are provided gs = self.gsf.get_ground_state() self.assertEqual(gs.get_chemical_formula(), "Au8Li8")