def setUp(self): mock_defect_species = create_mock_defect_species(2) mock_defects_at_site = create_mock_defects_at_site(2) with patch('pyscses.site.DefectAtSite', autospec=True) as mock_DefectAtSite: mock_DefectAtSite.side_effect = mock_defects_at_site self.site = Site(label='A', x=1.5, defect_species=mock_defect_species, defect_energies=[-0.2, +0.2])
def form_continuum_sites( all_sites, x_min, x_max, n_points, b, c, defect_species, limits_for_laplacian, site_labels, defect_labels ): """ Creates a Set_of_Sites object for sites interpolated onto a regular grid, this is equivalent to assuming a continuum approximation. Args: all_sites (object): Orginal Set_of_Sites object from full data. x_min (float): Minimum x coordinate value defining the calculation region. x_max (float): Maximum x coordinate value defining the calculation region. n_points (int): Number of points that the data should be interpolated on to. b (float): b dimension for every grid point. c (float): c dimension for every grid point. defect_species (object): Class object containing information about the defect species present in the system. limits for laplacian (list): distance between the endmost sites and the midpoint of the next site outside of the calculation region for the first and last sites respectively. site_labels( list ): List of strings for the different site species. defect_labels (list): List of strings for the different defect species. Returns: :obj:`Set_of_Sites`: Sites interpolated onto a regular grid. """ grid = np.linspace( x_min, x_max, n_points ) limits = [grid[1] - grid[0], grid[1] - grid[0]] sites = [] for label, d_label in zip(site_labels, defect_labels): scaling = len( all_sites.subset( label ) ) / len( grid ) continuum_grid = Grid( grid, b, c, limits, limits_for_laplacian, all_sites.subset( label ) ) average_energies = np.array( [ site.average_local_energy( method = 'mean' )[0] for site in all_sites.subset( label ) ] ) new_energies = griddata( ( [ site.x for site in all_sites.subset( label ) ] ), average_energies, grid, method = 'nearest' ) for x, e in zip( grid, new_energies): sites.append( Site( label, x, [ defect_species[ d_label ] ], [e], scaling = np.array( scaling ) ) ) return Set_of_Sites( sites ), limits
def form_continuum_sites_new(all_sites, x_min, x_max, n_points, b, c, defect_species, limits_for_laplacian, site_labels, defect_labels): limits = [x_min, x_max] grid = np.linspace(x_min, x_max, n_points) sites = [] for label, d_label in zip(site_labels, defect_labels): scaling = len(all_sites.subset(label)) / len(grid) continuum_grid = Grid(grid, b, c, limits, limits_for_laplacian, all_sites.subset(label)) average_energies = np.array([ site.average_local_energy(method='mean')[0] for site in all_sites.subset(label) ]) new_energies = griddata( ([site.x for site in all_sites.subset(label)]), Vo.average_energies, grid, method='nearest') for x, e in zip(grid, new_energies): sites.append( Site(label, x, [defect_species[d_label]], [e], scaling=np.array(scaling))) return Set_of_Sites(sites)
def test_site_init_data_check_1(self): """Checks that initialising a Site object raises a ValueError if n(defect_species) != n(defect_energies)""" mock_defect_species = create_mock_defect_species(1) with patch('pyscses.site.DefectAtSite', autospec=True) as mock_DefectAtSite: with self.assertRaises(ValueError): site = Site(label='A', x=1.5, defect_species=mock_defect_species, defect_energies=[-0.2, +0.2])
def test_site_init_with_mixed_mobile_and_fixed_defects(self): mock_defect_species = create_mock_defect_species(3) mock_defects_at_site = create_mock_defects_at_site(3) mock_defects_at_site[0].fixed = False mock_defects_at_site[0].mole_fraction = 0.4 mock_defects_at_site[1].fixed = True mock_defects_at_site[1].mole_fraction = 0.3 mock_defects_at_site[2].fixed = True mock_defects_at_site[2].mole_fraction = 0.2 with patch('pyscses.site.DefectAtSite', autospec=True) as mock_DefectAtSite: mock_DefectAtSite.side_effect = mock_defects_at_site site = Site(label='C', x=1.5, defect_species=mock_defect_species, defect_energies=[-0.2, +0.2, 0.0]) self.assertEqual(site.fixed_defects, (mock_defects_at_site[1], mock_defects_at_site[2])) self.assertEqual(site.mobile_defects[0], mock_defects_at_site[0]) self.assertEqual(site.alpha, 0.5)
def test_site_is_initialised_with_optional_args(self): mock_defect_species = create_mock_defect_species(2) with patch('pyscses.site.DefectAtSite', autospec=True) as mock_DefectAtSite: mock_DefectAtSite.side_effect = create_mock_defects_at_site(2) site = Site(label='B', x=1.5, defect_species=mock_defect_species, defect_energies=[-0.2, +0.2], scaling=[0.5, 0.4], valence=-2.0, saturation_parameter=0.1) self.assertEqual(site.label, 'B') self.assertEqual(site.x, 1.5) self.assertEqual(site.defect_species, mock_defect_species) self.assertEqual(site.defect_energies, [-0.2, +0.2]) np.testing.assert_equal(site.scaling, np.array([0.5, 0.4])) self.assertEqual(site.valence, -2.0) self.assertEqual(site.saturation_parameter, 0.1) self.assertEqual(site.alpha, 0.1)
def test_site_is_initialised(self): mock_defect_species = create_mock_defect_species(2) mock_defects_at_site = create_mock_defects_at_site(2) with patch('pyscses.site.DefectAtSite', autospec=True) as mock_DefectAtSite: mock_DefectAtSite.side_effect = mock_defects_at_site site = Site(label='A', x=1.5, defect_species=mock_defect_species, defect_energies=[-0.2, +0.2]) self.assertEqual(site.label, 'A') self.assertEqual(site.x, 1.5) self.assertEqual(site.defect_species, mock_defect_species) self.assertEqual(site.defect_energies, [-0.2, +0.2]) np.testing.assert_equal(site.scaling, np.array([1.0, 1.0])) self.assertEqual(site.valence, 0.0) self.assertEqual(site.saturation_parameter, 1.0) self.assertEqual(site.fixed_defects, ()) self.assertEqual(site.mobile_defects, tuple(mock_defects_at_site)) self.assertEqual(site.alpha, 1.0)
def site_from_input_file(site, defect_species, site_charge, temperature, zero_energies_less_than_kT=False): """ Takes the data from the input file and converts it into a site. The input data file is a .txt file where each line in the file corresponds to a site. The values in each line are formatted and separated into the corresponding properties before creating a Site object for each site. Args: site (str): A line in the input file. defect_species (object): Class object containing information about the defect species present in the system. site_charge (bool): The site charge refers to the contribution to the overall charge of a site given by the original, non-defective species present at that site. True if the site charge contribution is to be included in the calculation, False if it is not to be included. temperature (float): Temperature in Kelvin. zero_energies_less_than_kT (optional(bool)): If True segregation energies with absolute values < kT will be set to zero. Default is False. Returns: :obj:`Site` """ label = site[0] if site_charge == True: valence = float(site[1]) if site_charge == False: valence = 0.0 x = float(site[2]) defect_labels = site[3::2] defect_energies = [float(e) for e in site[4::2]] if zero_energies_less_than_kT: kT = boltzmann_eV * temperature for d_e in defect_energies: if abs(d_e) < kT: d_e = 0.0 return Site(label, x, [defect_species[l] for l in defect_labels],\ defect_energies, valence=valence)
def site_from_input_file(site, defect_species, site_charge, core, temperature): """ Takes the data from the input file and converts it into a site. The input data file is a .txt file where each line in the file corresponds to a site. The values in each line are formatted and separated into the corresponding properties before creating a Site object for each site. Args: site (str): A line in the input file. defect_species (object): Class object containing information about the defect species present in the system. site_charge (bool): The site charge refers to the contribution to the overall charge of a site given by the original, non-defective species present at that site. True if the site charge contribution is to be included in the calculation, False if it is not to be included. Returns: :obj:`Site` """ label = site[0] if site_charge == True: valence = float(site[1]) if site_charge == False: valence = 0.0 x = float(site[2]) defect_labels = site[3::2] defect_energies = [float(e) for e in site[4::2]] min_energy = min(defect_energies) if core == 'single': for d_e in defect_energies: if d_e > min_energy: d_e = 0.0 if core == 'multi-site': for d_e in defect_energies: if (-boltzmann_eV * temperature) <= d_e <= (boltzmann_eV * temperature): d_e = 0.0 #defect_energies = [ 0.0 for e in site[4::2] ] return Site(label, x, [defect_species[l] for l in defect_labels], defect_energies, valence=valence)
class TestSite(unittest.TestCase): def setUp(self): mock_defect_species = create_mock_defect_species(2) mock_defects_at_site = create_mock_defects_at_site(2) with patch('pyscses.site.DefectAtSite', autospec=True) as mock_DefectAtSite: mock_DefectAtSite.side_effect = mock_defects_at_site self.site = Site(label='A', x=1.5, defect_species=mock_defect_species, defect_energies=[-0.2, +0.2]) def test_defect_with_label(self): self.site.defects[0].label = 'foo' self.site.defects[1].label = 'bar' self.assertEqual(self.site.defect_with_label('foo'), self.site.defects[0]) self.assertEqual(self.site.defect_with_label('bar'), self.site.defects[1]) def test_defect_with_label_2(self): """Checks that defect_with_label() raises a LabelError if the argument does not match any of the defect labels for this site.""" self.site.defects[0].label = 'foo' self.site.defects[1].label = 'bar' with self.assertRaises(LabelError): self.site.defect_with_label('banana') def test_energies(self): self.site.defects[0].energy = -0.2 self.site.defects[1].energy = +0.2 self.assertEqual(self.site.energies(), [-0.2, +0.2]) def test_probabilities_one(self): self.site.defects[0].boltzmann_factor = Mock(return_value=0.1) self.site.defects[0].mole_fraction = 0.2 self.site.defects[0].label = 'A' self.site.defects[1].boltzmann_factor = Mock(return_value=0.1) self.site.defects[1].mole_fraction = 0.1 self.site.defects[1].label = 'B' exp_A = ((0.2 * 0.1 / (1.0 + (0.2 * (0.1 - 1.0) + 0.1 * (0.1 - 1.0))))) exp_B = ((0.1 * 0.1 / (1.0 + (0.2 * (0.1 - 1.0) + 0.1 * (0.1 - 1.0))))) self.assertEqual(self.site.probabilities(phi=1.0, temp=298.0), { 'A': exp_A, 'B': exp_B }) def test_probabilities_two(self): self.site.defects[0].boltzmann_factor = Mock(return_value=0.1) self.site.defects[0].mole_fraction = 0.2 self.site.defects[0].label = 'A' self.site.defects[0].fixed = True self.site.alpha = 0.8 self.site.fixed_defects = (self.site.defects[0], ) self.site.defects[1].boltzmann_factor = Mock(return_value=0.1) self.site.defects[1].mole_fraction = 0.1 self.site.defects[1].label = 'B' self.site.mobile_defects = (self.site.defects[1], ) exp_A = 0.2 exp_B = 0.8 * ((0.1 * 0.1 / (0.8 + (0.1 * (0.1 - 1.0))))) self.assertEqual(self.site.probabilities(phi=1.0, temp=298.0), { 'A': exp_A, 'B': exp_B }) def test_charge(self): self.site.probabilities = Mock(return_value={'E': 0.1, 'D': 0.2}) self.site.defects[0].valence = 1.0 self.site.defects[1].valence = 2.0 self.site.scaling = 0.5 self.site.valence = 1.0 expected_value = ( (1.0 * 0.1 + 2.0 * 0.2) * 0.5 + 1.0) * fundamental_charge self.assertEqual(self.site.charge(phi=1.0, temp=298.0), expected_value)