class TestStructureGenerationInactiveSublatticeSameSpeciesFCC(
        unittest.TestCase):
    """
    Container for tests of the class functionality
    """
    def __init__(self, *args, **kwargs):
        super(TestStructureGenerationInactiveSublatticeSameSpeciesFCC,
              self).__init__(*args, **kwargs)
        self.prim = bulk('Au', a=4.0)
        self.cs_with_only_active_sl = ClusterSpace(self.prim, [6.0, 5.0],
                                                   ['Au', 'Pd'])
        self.prim.append(Atom('Au', position=(2.0, 2.0, 2.0)))
        self.supercell = self.prim.repeat(3)
        self.cs = ClusterSpace(self.prim, [6.0, 5.0], [['Au', 'Pd'], ['Au']])

    def shortDescription(self):
        """Silences unittest from printing the docstrings in test cases."""
        return None

    def test_get_sqs_cluster_vector(self):
        """Test SQS cluster vector generation."""
        target_concentrations = {'Au': 0.7, 'Pd': 0.3}

        # It should be the same as for cs without inactive lattice
        target_cv = _get_sqs_cluster_vector(self.cs_with_only_active_sl,
                                            target_concentrations)
        cv = _get_sqs_cluster_vector(self.cs, target_concentrations)
        self.assertTrue(np.allclose(cv, target_cv))

        # Test also when inactive sublattice is specified
        target_concentrations = {'A': {'Au': 0.7, 'Pd': 0.3}, 'B': {'Au': 1}}
        cv = _get_sqs_cluster_vector(self.cs, target_concentrations)
        self.assertTrue(np.allclose(cv, target_cv))

        # It should be the same as for cs without inactive lattice
        target_cv = _get_sqs_cluster_vector(self.cs_with_only_active_sl,
                                            target_concentrations)
        cv = _get_sqs_cluster_vector(self.cs, target_concentrations)
        self.assertTrue(np.allclose(cv, target_cv))

    def test_validate_concentrations(self):
        """Tests validation of conecntrations against cluster space."""
        concentrations = {'Au': 0.4, 'Pd': 0.6}
        ret_conc = _validate_concentrations(concentrations, self.cs)
        self.assertIsInstance(ret_conc, dict)
        self.assertEqual(len(ret_conc), 1)
        self.assertIsInstance(ret_conc['A'], dict)

        concentrations = {'Au': 0.1, 'Pd': 0.8}
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn('Concentrations must sum up to 1', str(cm.exception))

        concentrations = {'A': {'Au': 0.4, 'Pd': 0.6}, 'B': {'Au': 1.0}}
        ret_conc = _validate_concentrations(concentrations, self.cs)
        self.assertIsInstance(ret_conc, dict)
        self.assertEqual(len(ret_conc), 2)
        self.assertIsInstance(ret_conc['A'], dict)

        concentrations = {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'C': 1}}
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn('not the same as those in the specified',
                      str(cm.exception))

    def test_occupy_structure_randomly(self):
        """Tests random occupation of ASE Atoms object"""
        structure = self.prim.repeat(2)
        target_concentrations = {'Au': 3 / 4, 'Pd': 1 / 4}
        occupy_structure_randomly(structure, self.cs, target_concentrations)
        syms = structure.get_chemical_symbols()
        self.assertEqual(syms.count('Au'),
                         3 * (len(structure) // 2) // 4 + len(structure) // 2)
        self.assertEqual(syms.count('Pd'), (len(structure) // 2) // 4)

    def test_generate_sqs_by_enumeration(self):
        """Test generation of SQS structure"""

        target_conc = {'Pd': 1 / 2, 'Au': 1 / 2}
        structure = generate_sqs_by_enumeration(
            cluster_space=self.cs,
            max_size=4,
            target_concentrations=target_conc,
            optimality_weight=0.0)
        target_cv = [
            1., 0., -0.16666667, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
        ]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))
class TestStructureGenerationBinaryFCC(unittest.TestCase):
    """
    Container for tests of the class functionality
    """
    def __init__(self, *args, **kwargs):
        super(TestStructureGenerationBinaryFCC, self).__init__(*args, **kwargs)
        self.prim = bulk('Au', a=4.0)
        self.supercell = self.prim.repeat(3)
        self.cs = ClusterSpace(self.prim, [6.0, 5.0], ['Au', 'Pd'])

    def shortDescription(self):
        """Silences unittest from printing the docstrings in test cases."""
        return None

    def test_get_sqs_cluster_vector(self):
        """Test SQS cluster vector generation."""
        target_concentrations = {'Au': 0.5, 'Pd': 0.5}
        target_vector = np.array([1.0] + [0.0] * (len(self.cs) - 1))
        cv = _get_sqs_cluster_vector(self.cs, target_concentrations)
        self.assertTrue(np.allclose(cv, target_vector))

        target_concentrations = {'A': {'Au': 0.15, 'Pd': 0.85}}
        target_vector = np.array([
            1., -0.7, 0.49, 0.49, 0.49, 0.49, -0.343, -0.343, -0.343, -0.343,
            -0.343, -0.343, -0.343
        ])
        cv = _get_sqs_cluster_vector(self.cs, target_concentrations)
        self.assertTrue(np.allclose(cv, target_vector))

    def test_validate_concentrations(self):
        """Tests validation of conecntrations against cluster space."""
        concentrations = {'Au': 0.5, 'Pd': 0.5}
        _validate_concentrations(concentrations, self.cs)

        concentrations = {'Au': 0.1, 'Pd': 0.7}
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn('Concentrations must sum up to 1', str(cm.exception))

        concentrations = {'Au': 0.1, 'Pd': 0.8, 'Cu': 0.1}
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn('not the same as those in the specified',
                      str(cm.exception))

        concentrations = {'Au': 1.0}
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn('not the same as those in the specified',
                      str(cm.exception))

    def test_concentrations_fit_structure(self):
        """
        Tests check of concentrations against an ASE Atoms object
        belonging to a cluster space
        """
        concentrations = {'A': {'Au': 1 / 3, 'Pd': 2 / 3}}
        self.assertTrue(
            _concentrations_fit_structure(self.supercell, self.cs,
                                          concentrations))

        concentrations = {'A': {'Au': 0.5, 'Pd': 0.5}}
        self.assertFalse(
            _concentrations_fit_structure(self.supercell, self.cs,
                                          concentrations))

    def test_occupy_structure_randomly(self):
        """Tests random occupation of ASE Atoms object"""
        structure = self.prim.repeat(2)
        target_concentrations = {'Au': 0.5, 'Pd': 0.5}
        occupy_structure_randomly(structure, self.cs, target_concentrations)
        syms = structure.get_chemical_symbols()
        self.assertEqual(syms.count('Au'), len(structure) // 2)

        structure = self.prim.repeat(3)
        target_concentrations = {'Au': 1 / 3, 'Pd': 2 / 3}
        occupy_structure_randomly(structure, self.cs, target_concentrations)
        syms = structure.get_chemical_symbols()
        self.assertEqual(syms.count('Au'), len(structure) // 3)
        self.assertEqual(syms.count('Pd'), 2 * len(structure) // 3)

    def test_generate_target_structure(self):
        """Test generation of a structure based on a target cluster vector"""
        # Exact target vector from 2 atoms cell
        # target_cv = np.array([1., 0., 0., -1., 0., 1.,
        #                      0., 0., 0., 0., 0., 0., 0.])
        target_cv = np.array(
            [1., 0., -1 / 3, 1., -1 / 3, 1., 0., 0., 0., 0., 0., 0., 0.])
        target_conc = {'Au': 0.5, 'Pd': 0.5}

        kwargs = dict(cluster_space=self.cs,
                      max_size=4,
                      target_concentrations=target_conc,
                      target_cluster_vector=target_cv,
                      n_steps=500,
                      random_seed=42,
                      optimality_weight=0.3)

        # This should be simple enough to always work
        structure = generate_target_structure(**kwargs)
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

        # Using include_smaller_cells = False
        structure = generate_target_structure(**kwargs,
                                              include_smaller_cells=False)
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

        # Using non-pbc
        structure = generate_target_structure(**kwargs,
                                              include_smaller_cells=False,
                                              pbc=(True, False, False))
        target_cell = [[0, 8, 8], [2, 0, 2], [2, 2, 0]]
        self.assertTrue(np.allclose(structure.cell, target_cell))
        target_cv = [1., 0., 0., -1., 0., 1., 0., 0., 0., 0., 0., 0., 0.]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

    def test_generate_target_from_supercells(self):
        """Test generation of a structure based on a target cluster vector and a list
        of supercells"""
        target_cv = [1., 0., 0., -1., 0., 1., 0., 0., 0., 0., 0., 0., 0.]
        target_conc = {'Au': 0.5, 'Pd': 0.5}
        kwargs = dict(cluster_space=self.cs,
                      target_concentrations=target_conc,
                      target_cluster_vector=target_cv,
                      n_steps=500,
                      random_seed=42,
                      optimality_weight=0.3)

        supercells = [self.prim.repeat((2, 2, 1)), self.prim.repeat((2, 1, 1))]
        # This should be simple enough to always work
        structure = generate_target_structure_from_supercells(
            supercells=supercells, **kwargs)
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

        # Log output to StringIO stream
        for handler in logger.handlers:
            handler.close()
            logger.removeHandler(handler)

        # Use supercells that do not fit
        supercells = [self.prim.repeat((2, 2, 1)), self.prim.repeat((3, 1, 1))]
        logfile = NamedTemporaryFile(mode='w+', encoding='utf-8')
        set_log_config(filename=logfile.name)
        structure = generate_target_structure_from_supercells(
            supercells=supercells, **kwargs)
        logfile.seek(0)
        lines = logfile.readlines()
        logfile.close()
        self.assertIn('At least one supercell was not commensurate', lines[0])
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

        # Use two supercells that do not fit
        supercells = [self.prim.repeat((3, 3, 1)), self.prim.repeat((3, 1, 1))]
        logfile = NamedTemporaryFile(mode='w+', encoding='utf-8')
        set_log_config(filename=logfile.name)
        with self.assertRaises(ValueError) as cm:
            generate_target_structure_from_supercells(supercells=supercells,
                                                      **kwargs)
        logfile.seek(0)
        lines = logfile.readlines()
        logfile.close()
        self.assertEqual(len(lines), 1)  # Warning should be issued once
        self.assertIn('At least one supercell was not commensurate', lines[0])
        self.assertIn('No supercells that may host the specified',
                      str(cm.exception))

    def test_generate_sqs(self):
        """Test generation of SQS structure"""

        kwargs = dict(cluster_space=self.cs,
                      max_size=4,
                      target_concentrations={
                          'Au': 0.5,
                          'Pd': 0.5
                      },
                      n_steps=500,
                      random_seed=42,
                      optimality_weight=0.0)

        # This should be simple enough to always work
        structure = generate_sqs(**kwargs)
        target_cv = [
            1., 0., -0.16666667, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
        ]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

        # Using-non pbc
        structure = generate_sqs(**kwargs, pbc=(False, True, False))
        target_cell = [[0, 2, 2], [8, 0, 8], [2, 2, 0]]
        self.assertTrue(np.allclose(structure.cell, target_cell))
        target_cv = [1., 0., 0.5, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

    def test_generate_sqs_from_supercells(self):
        """Test generation of SQS structure from list of supercells"""
        target_conc = {'Au': 0.5, 'Pd': 0.5}
        kwargs = dict(cluster_space=self.cs,
                      target_concentrations=target_conc,
                      n_steps=500,
                      random_seed=42,
                      optimality_weight=0.0)

        supercells = [self.prim.repeat((2, 2, 1)), self.prim.repeat((2, 1, 1))]
        structure = generate_sqs_from_supercells(supercells=supercells,
                                                 **kwargs)
        target_cv = [1., 0., 0., -1., 0., 1., 0., 0., 0., 0., 0., 0., 0.]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

        # Log output to StringIO stream
        for handler in logger.handlers:
            handler.close()
            logger.removeHandler(handler)

        # Test with supercell that does not match
        supercells = [self.prim]
        logfile = NamedTemporaryFile(mode='w+', encoding='utf-8')
        set_log_config(filename=logfile.name)
        with self.assertRaises(ValueError) as cm:
            generate_sqs_from_supercells(supercells=supercells, **kwargs)
        logfile.seek(0)
        lines = logfile.readlines()
        logfile.close()
        self.assertEqual(len(lines), 1)
        self.assertIn('At least one supercell was not commensurate', lines[0])
        self.assertIn('No supercells that may host the specified',
                      str(cm.exception))

    def test_generate_sqs_by_enumeration(self):
        """Test generation of SQS structure"""
        kwargs = dict(cluster_space=self.cs,
                      max_size=4,
                      target_concentrations={
                          'Au': 0.5,
                          'Pd': 0.5
                      },
                      optimality_weight=0.0)

        structure = generate_sqs_by_enumeration(**kwargs)
        target_cv = [
            1., 0., -0.16666667, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.
        ]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))

        # Using non-pbc
        structure = generate_sqs(**kwargs, pbc=(False, True, False))
        target_cell = [[0, 2, 2], [8, 0, 8], [2, 2, 0]]
        self.assertTrue(np.allclose(structure.cell, target_cell))
        target_cv = [1., 0., 0.5, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))
class TestStructureGenerationSublatticesFCC(unittest.TestCase):
    """
    Container for tests of the class functionality
    """
    def __init__(self, *args, **kwargs):
        super(TestStructureGenerationSublatticesFCC,
              self).__init__(*args, **kwargs)
        self.prim = bulk('Au', a=4.0)
        self.prim.append(Atom('H', position=(2.0, 2.0, 2.0)))
        self.supercell = self.prim.repeat(3)
        self.cs = ClusterSpace(self.prim, [5.0, 4.0],
                               [['Au', 'Pd', 'Cu'], ['H', 'V']])

    def shortDescription(self):
        """Silences unittest from printing the docstrings in test cases."""
        return None

    def test_get_sqs_cluster_vector(self):
        """Test SQS cluster vector generation."""
        target_concentrations = {
            'A': {
                'Au': 0.4,
                'Pd': 0.2,
                'Cu': 0.4
            },
            'B': {
                'H': 0.5,
                'V': 0.5
            }
        }
        cv = _get_sqs_cluster_vector(self.cs, target_concentrations)
        target_vector = [
            1., -0.1, 0.17320508, 0., 0., 0., 0.01, -0.01732051, 0.03, 0., 0.,
            0., 0.01, -0.01732051, 0.03, 0., 0., 0., 0.01, -0.01732051, 0.03,
            0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            -0.001, 0.00173205, -0.003, 0.00519615, 0., -0.001, 0.00173205,
            0.00173205, -0.003, -0.003, 0.00519615, 0., 0., 0., 0., 0., 0.
        ]
        self.assertTrue(np.allclose(cv, target_vector))

    def test_validate_concentrations(self):
        """Tests validation of conecntrations against cluster space."""
        concentrations = {
            'A': {
                'Au': 0.2,
                'Pd': 0.6,
                'Cu': 0.2
            },
            'B': {
                'H': 0.8,
                'V': 0.2
            }
        }
        ret_conc = _validate_concentrations(concentrations, self.cs)
        self.assertIsInstance(ret_conc, dict)
        self.assertEqual(len(ret_conc), 2)
        self.assertIsInstance(ret_conc['A'], dict)

        concentrations = {
            'A': {
                'Au': 0.1,
                'Pd': 0.7,
                'Cu': 0.2
            },
            'B': {
                'H': 0.0,
                'V': 0.9
            }
        }
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn('Concentrations must sum up to 1', str(cm.exception))

        concentrations = {'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'Cu': 1}}
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn('not the same as those in the specified',
                      str(cm.exception))

        concentrations = {'Au': 2 / 6, 'Pd': 1 / 6, 'Cu': 3 / 6}
        with self.assertRaises(ValueError) as cm:
            _validate_concentrations(concentrations, self.cs)
        self.assertIn("A sublattice (B: ['H', 'V']) is missing",
                      str(cm.exception))

    def test_concentrations_fit_structure(self):
        """
        Tests check of concentrations against an ASE Atoms object
        belonging to a cluster space
        """
        concentrations = {
            'A': {
                'Au': 1 / 3,
                'Pd': 1 / 3,
                'Cu': 1 / 3
            },
            'B': {
                'H': 2 / 3,
                'V': 1 / 3
            }
        }
        self.assertTrue(
            _concentrations_fit_structure(self.supercell, self.cs,
                                          concentrations))

        concentrations = {
            'A': {
                'Au': 1 / 2,
                'Pd': 1 / 4,
                'Cu': 1 / 4
            },
            'B': {
                'H': 2 / 3,
                'V': 1 / 3
            }
        }
        self.assertFalse(
            _concentrations_fit_structure(self.supercell, self.cs,
                                          concentrations))

    def test_occupy_structure_randomly(self):
        """Tests random occupation of ASE Atoms object"""
        structure = self.prim.repeat(2)
        target_concentrations = {
            'A': {
                'Cu': 1 / 4,
                'Au': 2 / 4,
                'Pd': 1 / 4
            },
            'B': {
                'H': 3 / 4,
                'V': 1 / 4
            }
        }
        occupy_structure_randomly(structure, self.cs, target_concentrations)
        syms = structure.get_chemical_symbols()
        self.assertEqual(syms.count('Cu'), len(structure) // 8)
        self.assertEqual(syms.count('Au'), len(structure) // 4)
        self.assertEqual(syms.count('Pd'), len(structure) // 8)
        self.assertEqual(syms.count('H'), 3 * len(structure) // 8)
        self.assertEqual(syms.count('V'), len(structure) // 8)

    def test_generate_sqs_by_enumeration(self):
        """Test generation of SQS structure"""

        target_conc = {
            'A': {
                'Cu': 1 / 4,
                'Au': 2 / 4,
                'Pd': 1 / 4
            },
            'B': {
                'H': 3 / 4,
                'V': 1 / 4
            }
        }
        structure = generate_sqs_by_enumeration(
            cluster_space=self.cs,
            max_size=4,
            include_smaller_cells=False,
            target_concentrations=target_conc,
            optimality_weight=1.0)
        target_cv = [
            1.00000000e+00, 1.25000000e-01, 2.16506351e-01, -5.00000000e-01,
            -1.25000000e-01, -7.21687836e-02, -3.12500000e-02, -1.85037171e-17,
            -3.12500000e-02, 1.66666667e-01, 3.12500000e-02, -1.62379763e-01,
            -1.25000000e-01, 1.08253175e-01, -3.70074342e-17, 0.00000000e+00,
            -6.25000000e-02, -1.08253175e-01, 1.56250000e-02, 2.70632939e-02,
            4.68750000e-02, 2.50000000e-01, -9.25185854e-18, 1.80421959e-02,
            6.25000000e-02, 8.33333333e-02, -3.70074342e-17, -2.22044605e-16,
            -2.52590743e-01, -1.25000000e-01, 1.25000000e-01, -7.21687836e-02,
            -1.56250000e-02, 4.51054898e-02, -8.11898816e-02, 4.68750000e-02,
            5.20833333e-02, 1.80421959e-02, -1.56250000e-02, -1.35316469e-02,
            -1.56250000e-02, -4.05949408e-02, 0.00000000e+00, -6.25000000e-02,
            2.54426110e-17, -5.41265877e-02, 3.12500000e-02, -3.23815049e-17,
            -5.41265877e-02, 1.66666667e-01, 1.56250000e-01, -8.78926561e-17,
            -9.37500000e-02, -1.87500000e-01, 1.08253175e-01
        ]
        self.assertTrue(
            np.allclose(self.cs.get_cluster_vector(structure), target_cv))
Exemplo n.º 4
0
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")
def generate_sqs_by_enumeration(cluster_space: ClusterSpace,
                                max_size: int,
                                target_concentrations: dict,
                                include_smaller_cells: bool = True,
                                pbc: Union[Tuple[bool, bool, bool],
                                           Tuple[int, int, int]] = None,
                                optimality_weight: float = 1.0,
                                tol: float = 1e-5) -> Atoms:
    """
    Given a ``cluster_space``, generate a special quasirandom structure
    (SQS), i.e., a structure that for a given supercell size provides
    the best possible approximation to a random alloy [ZunWeiFer90]_.

    In the present case, this means that the generated structure will
    have a cluster vector that as closely as possible matches the
    cluster vector of an infintely large randomly occupied supercell.
    Internally the function uses a simulated annealing algorithm and the
    difference between two cluster vectors is calculated with the
    measure suggested by A. van de Walle et al. in Calphad **42**, 13-18
    (2013) [WalTiwJon13]_ (for more information, see
    :class:`mchammer.calculators.TargetVectorCalculator`).

    This functions generates SQS cells by exhaustive enumeration, which
    means that the generated SQS cell is guaranteed to be optimal with
    regard to the specified measure and cell size.

    Parameters
    ----------
    cluster_space
        a cluster space defining the lattice to be occupied
    max_size
        maximum supercell size
    target_concentrations
        concentration of each species in the target structure, per
        sublattice (for example ``{'Au': 0.5, 'Pd': 0.5}`` for a
        single sublattice Au-Pd structure, or
        ``{'A': {'Au': 0.5, 'Pd': 0.5}, 'B': {'H': 0.25, 'X': 0.75}}``
        for a system with two sublattices.
        The symbols defining sublattices ('A', 'B' etc) can be
        found by printing the `cluster_space`
    include_smaller_cells
        if True, search among all supercell sizes including
        ``max_size``, else search only among those exactly matching
        ``max_size``
    pbc
        Periodic boundary conditions for each direction, e.g.,
        ``(True, True, False)``. The axes are defined by
        the cell of ``cluster_space.primitive_structure``.
        Default is periodic boundary in all directions.
    optimality_weight
        controls weighting :math:`L` of perfect correlations, see
        :class:`mchammer.calculators.TargetVectorCalculator`
    tol
        Numerical tolerance
    """
    target_concentrations = _validate_concentrations(target_concentrations,
                                                     cluster_space)
    sqs_vector = _get_sqs_cluster_vector(
        cluster_space=cluster_space,
        target_concentrations=target_concentrations)
    # Translate concentrations to the format required for concentration
    # restricted enumeration
    cr = {}  # type: Dict[str, tuple]
    sublattices = cluster_space.get_sublattices(
        cluster_space.primitive_structure)
    for sl in sublattices:
        mult_factor = len(sl.indices) / len(cluster_space.primitive_structure)
        if sl.symbol in target_concentrations:
            sl_conc = target_concentrations[sl.symbol]
        else:
            sl_conc = {sl.chemical_symbols[0]: 1.0}
        for species, value in sl_conc.items():
            c = value * mult_factor
            if species in cr:
                cr[species] = (cr[species][0] + c, cr[species][1] + c)
            else:
                cr[species] = (c, c)

    # Check to be sure...
    c_sum = sum(c[0] for c in cr.values())
    assert abs(c_sum - 1) < tol  # Should never happen, but...

    orbit_data = cluster_space.orbit_data
    best_score = 1e9

    if include_smaller_cells:
        sizes = list(range(1, max_size + 1))
    else:
        sizes = [max_size]

    # Prepare primitive structure with the right boundary conditions
    prim = cluster_space.primitive_structure
    if pbc is None:
        pbc = (True, True, True)
    prim.set_pbc(pbc)

    # Enumerate and calculate score for each structuer
    for structure in enumerate_structures(prim,
                                          sizes,
                                          cluster_space.chemical_symbols,
                                          concentration_restrictions=cr):
        cv = cluster_space.get_cluster_vector(structure)
        score = compare_cluster_vectors(cv_1=cv,
                                        cv_2=sqs_vector,
                                        orbit_data=orbit_data,
                                        optimality_weight=optimality_weight,
                                        tol=tol)

        if score < best_score:
            best_score = score
            best_structure = structure
    return best_structure
from ase.build import bulk, cut
from icet import ClusterSpace

# initializes cluster space and get the internal primitive structure
prim = bulk('Au', a=4.0, crystalstructure='hcp')
subelements = ['Au', 'Pd']
cutoffs = [0.0]

cs = ClusterSpace(prim, cutoffs, subelements)
structure_prim = cs.primitive_structure

# create a supercell using permutation matrix
p_trial = [[1, 0, 0], [0, 1, 5], [0, 0, 2]]
supercell = cut(structure_prim, p_trial[0], p_trial[1], p_trial[2])

# setup cartesian input to generate a random population
cartesian_product_input = []
for i in range(len(supercell)):
    cartesian_product_input.append(['Pd', 'Au'])

# loop over element combinations and assert expected singlet value
for subset in itertools.product(*cartesian_product_input):
    for atom, element in zip(supercell, subset):
        atom.symbol = element
    cv = cs.get_cluster_vector(supercell)
    expected_singlet = -supercell.get_chemical_symbols().count('Pd')
    expected_singlet += supercell.get_chemical_symbols().count('Au')
    expected_singlet /= len(supercell)
    npt.assert_almost_equal(cv[1], expected_singlet)
Exemplo n.º 7
0
from icet.tools.structure_generation import (generate_sqs,
                                             generate_sqs_from_supercells,
                                             generate_sqs_by_enumeration,
                                             generate_target_structure)

from icet.input_output.logging_tools import set_log_config
set_log_config(level='INFO')

# Generate SQS for binary fcc, 50 % concentration
primitive_structure = bulk('Au')
cs = ClusterSpace(primitive_structure, [8.0, 4.0], ['Au', 'Pd'])
target_concentrations = {'Au': 0.5, 'Pd': 0.5}
sqs = generate_sqs(cluster_space=cs,
                   max_size=8,
                   target_concentrations=target_concentrations)
print('Cluster vector of generated structure:', cs.get_cluster_vector(sqs))

# Generate SQS for binary fcc with specified supercells
supercells = [primitive_structure.repeat((1, 2, 4))]
sqs = generate_sqs_from_supercells(cluster_space=cs,
                                   supercells=supercells,
                                   n_steps=10000,
                                   target_concentrations=target_concentrations)
print('Cluster vector of generated structure:', cs.get_cluster_vector(sqs))

# Use enumeration to generate SQS for binary fcc, 50 % concentration
sqs = generate_sqs_by_enumeration(cluster_space=cs,
                                  max_size=8,
                                  target_concentrations=target_concentrations)
print('Cluster vector of generated structure:', cs.get_cluster_vector(sqs))
Exemplo n.º 8
0
                  cutoffs=[7.0, 5.0, 4.0],
                  chemical_symbols=[['Au', 'Pd', 'Cu'], ['H', 'V']])

A = np.random.random((n, len(cs)))
y = np.random.random(n)  # Add 10 so we are sure nothing gets zero by accident

c = get_mixing_energy_constraints(cs)
Ac = c.transform(A)
opt = Optimizer((Ac, y), fit_method='ridge')
opt.train()

parameters = c.inverse_transform(opt.parameters)

for syms in itertools.product(['Au', 'Pd', 'Cu'], ['H', 'V']):
    prim.set_chemical_symbols(syms)
    assert abs(np.dot(parameters, cs.get_cluster_vector(prim))) < 1e-12

# Test get_mixing_energy_constraints for structure with multiple atoms in sublattice
prim = bulk('Ti', crystalstructure='hcp')
chemical_symbols = ['Ti', 'W', 'V']
cs = ClusterSpace(prim,
                  cutoffs=[7.0, 5.0, 4.0],
                  chemical_symbols=chemical_symbols)

A = np.random.random((n, len(cs)))
y = np.random.random(
    n) + 10.0  # Add 10 so we are sure nothing gets zero by accident

c = get_mixing_energy_constraints(cs)
Ac = c.transform(A)
opt = Optimizer((Ac, y), fit_method='ridge')
# Construct test structure
P = [[4, 1, -3], [1, 3, 1], [-1, 1, 3]]
structure = make_supercell(reference, P)

# Change some elements
to_delete = []
for atom in structure:
    if atom.position[2] < 10.0:
        if atom.symbol == 'Y':
            atom.symbol = 'Al'
        elif atom.symbol == 'O':
            atom.symbol = 'X'
del structure[to_delete]

# Calculate cluster vector of ideal mapped_structure
cv_ideal = cs.get_cluster_vector(structure)

# Add some strain
A = [[1.04, 0.03, 0], [0, 1, 0], [0, 0, 1]]
structure.set_cell(np.dot(structure.cell, A), scale_atoms=True)

# Remove vacancies
del structure[[atom.index for atom in structure if atom.symbol == 'X']]

# Rattle the structure
rattle = [[-0.2056, 0.177, -0.586], [-0.1087, -0.0637, 0.0402],
          [0.2378, 0.0254, 0.1339], [-0.0932, 0.1039, 0.1613],
          [-0.3034, 0.03, 0.0373], [0.1191, -0.4569, -0.2607],
          [0.4468, -0.1684, 0.156], [-0.2064, -0.2069, -0.1834],
          [-0.1518, -0.1406, 0.0796], [0.0735, 0.3443, 0.2036],
          [-0.1934, 0.0082, 0.1599], [-0.2035, -0.1698, -0.4892],
class TestStructureContainer(unittest.TestCase):
    """Container for tests of the class functionality."""

    def __init__(self, *args, **kwargs):
        super(TestStructureContainer, self).__init__(*args, **kwargs)
        prim = bulk('Ag', a=4.09)
        chemical_symbols = ['Ag', 'Au']
        self.cs = ClusterSpace(structure=prim,
                               cutoffs=[4.0, 4.0, 4.0],
                               chemical_symbols=chemical_symbols)
        self.structure_list = []
        self.user_tags = []
        for k in range(4):
            structure = prim.repeat(2)
            symbols = [chemical_symbols[0]] * len(structure)
            symbols[:k] = [chemical_symbols[1]] * k
            structure.set_chemical_symbols(symbols)
            self.structure_list.append(structure)
            self.user_tags.append('Structure {}'.format(k))

        self.properties_list = []
        self.add_properties_list = []
        for k, structure in enumerate(self.structure_list):
            structure.set_calculator(EMT())
            properties = {'energy': structure.get_potential_energy(),
                          'volume': structure.get_volume(),
                          'Au atoms': structure.get_chemical_symbols().count('Au')}
            self.properties_list.append(properties)
            add_properties = {'total_energy': structure.get_total_energy()}
            self.add_properties_list.append(add_properties)

    def shortDescription(self):
        """Silences unittest from printing the docstrings in test cases."""
        return None

    def setUp(self):
        """Instantiates class before each test."""
        self.sc = StructureContainer(self.cs)
        for structure, tag, props in zip(self.structure_list,
                                         self.user_tags,
                                         self.properties_list):
            self.sc.add_structure(structure, tag, props)

    def test_init(self):
        """Tests that initialization of tested class works."""
        # check empty initialization
        self.assertIsInstance(StructureContainer(self.cs), StructureContainer)

        # check whether method raises Exceptions
        with self.assertRaises(TypeError) as cm:
            StructureContainer('my_sc.sc')
        self.assertIn('cluster_space must be a ClusterSpace', str(cm.exception))

    def test_len(self):
        """Tests length functionality."""
        len_structure_container = self.sc.__len__()
        self.assertEqual(len_structure_container, len(self.structure_list))

    def test_getitem(self):
        """Tests getitem functionality."""
        structure = self.sc.__getitem__(1)
        self.assertIsNotNone(structure)

    def test_get_structure_indices(self):
        """Tests get_structure_indices functionality."""
        list_index = [x for x in range(len(self.structure_list))]
        self.assertEqual(self.sc.get_structure_indices(), list_index)

    def test_add_structure(self):
        """Tests add_structure functionality."""
        # add structure with tag and property
        structure = self.structure_list[0]
        properties = self.properties_list[0]
        tag = 'Structure 4'
        self.sc.add_structure(structure, tag, properties)
        self.assertEqual(len(self.sc), len(self.structure_list) + 1)

        # add atom and read property from calculator
        self.sc.add_structure(structure)
        self.assertEqual(len(self.sc), len(self.structure_list) + 2)
        self.assertEqual(self.sc[5].properties['energy'],
                         self.properties_list[0]['energy'] / len(structure))

        # add atom and don't read property from calculator
        structure_cpy = structure.copy()
        structure_cpy.set_calculator(EMT())
        self.sc.add_structure(structure_cpy)
        self.assertEqual(len(self.sc), len(self.structure_list) + 3)
        self.assertNotIn('energy', self.sc[6].properties)

        # check that duplicate structure is not added.
        with self.assertRaises(ValueError) as cm:
            self.sc.add_structure(structure, allow_duplicate=False)
        msg = 'Input structure and Structure 0 have identical ' \
              'cluster vectors at index 0'

        self.assertEqual(msg, str(cm.exception))
        self.assertEqual(len(self.sc), len(self.structure_list) + 3)

        symbols = ['Au' for i in range(len(structure))]
        structure.set_chemical_symbols(symbols)
        self.sc.add_structure(structure, 'Structure 5', allow_duplicate=False)
        self.assertEqual(len(self.sc), len(self.structure_list) + 4)

    def test_get_condition_number(self):
        """Tests get_condition_number functionality."""
        target = np.linalg.cond(self.sc.get_fit_data()[0])
        retval = self.sc.get_condition_number()

        self.assertEqual(target, retval)

    def test_get_fit_data(self):
        """Tests get_fit_data functionality."""
        import numpy as np
        cluster_vectors, properties = self.sc.get_fit_data()
        # testing outputs have ndarray type
        self.assertIsInstance(cluster_vectors, np.ndarray)
        self.assertIsInstance(properties, np.ndarray)
        # testing values of cluster_vectors and properties
        for structure, cv in zip(self.structure_list, cluster_vectors):
            retval = list(cv)
            target = list(self.cs.get_cluster_vector(structure))
            self.assertAlmostEqual(retval, target, places=9)
        for target, retval in zip(self.properties_list, properties):
            self.assertEqual(retval, target['energy'])
        # passing a list of indexes
        cluster_vectors, properties = self.sc.get_fit_data([0])
        retval = list(cluster_vectors[0])
        structure = self.structure_list[0]
        target = list(self.cs.get_cluster_vector(structure))
        self.assertAlmostEqual(retval, target, places=9)
        retval2 = properties[0]
        target2 = self.properties_list[0]
        self.assertEqual(retval2, target2['energy'])

    def test_repr(self):
        """Tests repr functionality."""
        retval = self.sc.__repr__()
        target = """
================================ Structure Container =================================
Total number of structures: 4
--------------------------------------------------------------------------------------
index | user_tag    | n_atoms | chemical formula | Au atoms | energy    | volume   
--------------------------------------------------------------------------------------
0     | Structure 0 | 8       | Ag8              | 0        |    0.0127 |  136.8359
1     | Structure 1 | 8       | Ag7Au            | 1        |   -0.0073 |  136.8359
2     | Structure 2 | 8       | Ag6Au2           | 2        |   -0.0255 |  136.8359
3     | Structure 3 | 8       | Ag5Au3           | 3        |   -0.0382 |  136.8359
======================================================================================
"""  # noqa
        self.assertEqual(strip_surrounding_spaces(target),
                         strip_surrounding_spaces(retval))

        # test representation of an empty structure container
        sc = StructureContainer(self.cs)
        self.assertEqual(sc.__repr__(), 'Empty StructureContainer')

    def test_get_string_representation(self):
        """Tests _get_string_representation functionality."""
        retval = self.sc._get_string_representation(print_threshold=2)
        target = """
================================ Structure Container =================================
Total number of structures: 4
--------------------------------------------------------------------------------------
index | user_tag    | n_atoms | chemical formula | Au atoms | energy    | volume   
--------------------------------------------------------------------------------------
0     | Structure 0 | 8       | Ag8              | 0        |    0.0127 |  136.8359
 ...
3     | Structure 3 | 8       | Ag5Au3           | 3        |   -0.0382 |  136.8359
======================================================================================
"""  # noqa
        self.assertEqual(strip_surrounding_spaces(target),
                         strip_surrounding_spaces(retval))

    def test_print_overview(self):
        """Tests print_overview functionality."""
        with StringIO() as capturedOutput:
            sys.stdout = capturedOutput  # redirect stdout
            self.sc.print_overview()
            sys.stdout = sys.__stdout__  # reset redirect
            self.assertTrue('Structure Container' in capturedOutput.getvalue())

    def test_cluster_space(self):
        """Tests cluster space functionality."""
        cs_onlyread = self.sc.cluster_space
        self.assertEqual(str(cs_onlyread), str(self.cs))

    def test_available_properties(self):
        """Tests available_properties property."""
        available_properties = sorted(self.properties_list[0])
        self.sc.add_structure(self.structure_list[0], properties=self.properties_list[0])

        self.assertSequenceEqual(available_properties, self.sc.available_properties)

    def test_read_write(self):
        """Tests the read and write functionality."""
        temp_file = tempfile.NamedTemporaryFile()

        # check before with a non-tar file
        with self.assertRaises(TypeError) as context:
            self.sc.read(temp_file)
        self.assertTrue('{} is not a tar file'.format(str(temp_file.name))
                        in str(context.exception))

        # save and read an empty structure container
        sc = StructureContainer(self.cs)
        sc.write(temp_file.name)
        sc_read = StructureContainer.read(temp_file.name)
        self.assertEqual(sc_read.__str__(), 'Empty StructureContainer')

        # save to file
        self.sc.write(temp_file.name)

        # read from file object
        sc_read = self.sc.read(temp_file.name)

        # check data
        self.assertEqual(len(self.sc), len(sc_read))
        self.assertEqual(self.sc.__str__(), sc_read.__str__())

        for fs, fs_read in zip(self.sc._structure_list, sc_read._structure_list):
            self.assertEqual(list(fs.cluster_vector),
                             list(fs_read.cluster_vector))
            self.assertEqual(fs.structure, fs_read.structure)
            self.assertEqual(fs.user_tag, fs_read.user_tag)
            self.assertEqual(fs.properties, fs_read.properties)
        temp_file.close()
Exemplo n.º 11
0
    # read cells, positions, atomic_numbers, nframes and energies
    with open(os.path.join(cwd, 'cells.raw'), 'rb') as f:
        cells = numpy.loadtxt(f)
    with open(os.path.join(cwd, 'coordinates.raw'), 'rb') as f:
        positions = numpy.loadtxt(f)
    with open(os.path.join(cwd, 'atomic_numbers.raw'), 'rb') as f:
        atomic_numbers = numpy.loadtxt(f, dtype=int)
    with open(os.path.join(cwd, 'natoms.raw'), 'rb') as f:
        natoms = numpy.loadtxt(f, dtype=int)
    with open(os.path.join(cwd, 'energies.raw'), 'rb') as f:
        energies = numpy.loadtxt(f)

    structurelist = create_structurelist(cells, positions, atomic_numbers,
                                         natoms)

    cv_list = numpy.array([cs.get_cluster_vector(s) for s in structurelist])

    fit_method = data.get('fit_method', 'lasso')
    start_time = time.time()
    opt = CrossValidationEstimator(fit_data=(cv_list, energies),
                                   fit_method='lasso')
    opt.validate()
    opt.train()

    ce = ClusterExpansion(cluster_space=cs,
                          parameters=opt.parameters,
                          metadata=opt.summary)
    ce.write('model.ce')
    run_time = time.time() - start_time

    print_runing_info(run_time)
class TestFitStructure(unittest.TestCase):
    """Container for tests of the class functionality."""

    def __init__(self, *args, **kwargs):
        super(TestFitStructure, self).__init__(*args, **kwargs)
        self.prim = bulk('Ag', a=4.09)
        self.cs = ClusterSpace(structure=self.prim, cutoffs=[4.0, 4.0, 4.0],
                               chemical_symbols=['Ag', 'Au'])

        self.structure = self.prim.repeat(2)
        self.prop = {'energy': 0.0126746}
        self.cv = self.cs.get_cluster_vector(self.structure)
        self.tag = 'struct1'

    def shortDescription(self):
        """Silences unittest from printing the docstrings in test cases."""
        return None

    def setUp(self):
        """Instantiates class before each test."""
        self.fit_structure = FitStructure(self.structure, self.tag, self.cv, self.prop)

    def test_init(self):
        """Tests that initialization of tested class works."""
        structure = self.prim.repeat(2)
        tag = 'struct1'
        self.fit_structure = FitStructure(structure, tag, [1, 2, 3, 4])

    def test_cluster_vector(self):
        """Tests cluster vector attribute."""
        structure = self.prim.repeat(2)
        cv_from_cluster_space = list(self.cs.get_cluster_vector(structure))
        cv = list(self.fit_structure.cluster_vector)
        self.assertEqual(cv, cv_from_cluster_space)

    def test_structure(self):
        """Tests structure attribute."""
        structure = self.fit_structure.structure
        self.assertTrue(isinstance(structure, Atoms))

    def test_user_tag(self):
        """Tests user_tag attribute."""
        user_tag = self.fit_structure.user_tag
        self.assertTrue(isinstance(user_tag, str))

    def test_properties(self):
        """Tests properties attribute."""
        properties = self.fit_structure.properties
        self.assertTrue(isinstance(properties, dict))

    def test_getattr(self):
        """Tests custom getattr function."""
        properties = dict(energy=2.123, nvac=48, c=[0.5, 0.5], fname='asd.xml')
        fs = FitStructure(self.structure, self.tag, self.cv, properties)

        # test the function call
        for key, val in properties.items():
            self.assertEqual(fs.__getattr__(key), val)

        # test the attributes
        self.assertEqual(fs.energy, properties['energy'])
        self.assertEqual(fs.nvac, properties['nvac'])
        self.assertEqual(fs.c, properties['c'])
        self.assertEqual(fs.fname, properties['fname'])

        # test regular attribute call
        fs.properties
        fs.structure
        with self.assertRaises(AttributeError):
            fs.hello_world
import inspect
import os
import numpy as np
from ase.build import bulk
from ase.db import connect
from icet import ClusterSpace

prim = bulk('Au', a=4.0, crystalstructure='hcp')
cutoffs = [7.0, 7.0, 7.0]
chemical_symbols = ['Au', 'Pd']
cs = ClusterSpace(prim, cutoffs, chemical_symbols)

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
db = connect(
    os.path.join(path,
                 '../../structure_databases/equivalent_structure_pairs.db'))

# Loop over all pairs
for structure in db.select():
    # Do not check the pair that was just checked
    if structure.equivalent_structure < structure.id:
        continue

    cv_1 = cs.get_cluster_vector(structure.toatoms())
    cv_2 = cs.get_cluster_vector(
        db.get(structure.equivalent_structure).toatoms())

    assert np.all(np.abs(cv_2 - cv_1) < 1e-6)
Exemplo n.º 14
0
"""
This example demonstrates how to construct cluster vectors.
"""

# Import modules
from ase.build import bulk
from icet import ClusterSpace

# Create a primitive structure, decide which additional elements to populate
# it with (Si, Ge) and set the cutoffs for pairs (5.0 Å), triplets (5.0 Å)
# and quadruplets (5.0 Å).
primitive_structure = bulk('Si')
cutoffs = [5.0, 5.0, 5.0]
subelements = ['Si', 'Ge']

# Initiate and print the cluster space.
cluster_space = ClusterSpace(primitive_structure, cutoffs, subelements)
print(cluster_space)

# Generate and print the cluster vector for a pure Si 2x2x2 supercell.
structure_1 = bulk('Si').repeat(2)
cluster_vector_1 = cluster_space.get_cluster_vector(structure_1)
print(cluster_vector_1)

# Generate and print the cluster vector for a mixed Si-Ge 2x2x2 supercell
structure_2 = bulk('Si').repeat(2)
structure_2[0].symbol = 'Ge'
cluster_vector_2 = cluster_space.get_cluster_vector(structure_2)
print(cluster_vector_2)
Exemplo n.º 15
0
from icet import ClusterSpace

cutoffs = [8.0, 7.0]
chemical_symbols = ['W', 'Ti']
prototype = bulk('W')
cs = ClusterSpace(prototype, cutoffs, chemical_symbols)

# testing info functionality
with StringIO() as capturedOutput:
    sys.stdout = capturedOutput
    cs.print_overview()
    sys.stdout = sys.__stdout__
    assert 'Cluster Space' in capturedOutput.getvalue()

# structure #1
cv = cs.get_cluster_vector(prototype)
cv_target = np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
                      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
                      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
                      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
                      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
                      1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
assert np.all(np.abs(cv_target - cv) < 1e-6)

# structure #2
conf = make_supercell(prototype, [[2, 0, 1],
                                  [0, 1, 0],
                                  [0, 1, 2]])
conf[0].symbol = 'Ti'
conf[1].symbol = 'Ti'
cv = cs.get_cluster_vector(conf)
Exemplo n.º 16
0
def get_average_cluster_vectors_wl(
        dcs: Union[WangLandauDataContainer, dict],
        cluster_space: ClusterSpace,
        temperatures: List[float],
        boltzmann_constant: float = kB,
        fill_factor_limit: float = None) -> DataFrame:
    """Returns the average cluster vectors from a :ref:`Wang-Landau simulation
    <wang_landau_ensemble>` for the temperatures specified.

    Parameters
    ----------
    dcs
        data container(s), from which to extract density of states
        as well as observables
    cluster_space
        cluster space to use for calculation of cluster vectors
    temperatures
        temperatures, at which to compute the averages
    boltzmann_constant
        Boltzmann constant :math:`k_B` in appropriate
        units, i.e. units that are consistent
        with the underlying cluster expansion
        and the temperature units [default: eV/K]
    fill_factor_limit
        use data recorded up to the point when the specified fill factor limit
        was reached when computing the average cluster vectors; otherwise use
        data for the last state

    Raises
    ------
    ValueError
        if the data container(s) do(es) not contain entropy data
        from Wang-Landau simulation
    """

    # fetch potential and structures
    if isinstance(dcs, WangLandauDataContainer):
        potential, trajectory = dcs.get('potential',
                                        'trajectory',
                                        fill_factor_limit=fill_factor_limit)
        energy_spacing = dcs.ensemble_parameters['energy_spacing']
    elif isinstance(dcs, dict) and isinstance(dcs[next(iter(dcs))],
                                              WangLandauDataContainer):
        potential, trajectory = [], []
        for dc in dcs.values():
            p, t = dc.get('potential',
                          'trajectory',
                          fill_factor_limit=fill_factor_limit)
            potential.extend(p)
            trajectory.extend(t)
        energy_spacing = list(
            dcs.values())[0].ensemble_parameters['energy_spacing']
        potential = np.array(potential)
    else:
        raise TypeError('dcs ({}) must be a data container with entropy data'
                        ' or be a list of data containers'.format(type(dcs)))

    # fetch entropy and density of states from data container(s)
    df_density, _ = get_density_of_states_wl(dcs, fill_factor_limit)

    # compute weighted density and cluster vector for each bin in energy
    # range; the weighted density is the total density divided by the number
    # of structures that fall in the respective bin
    # NOTE: the following code relies on the indices of the df_density
    # DataFrame to correspond to the energy scale. This is expected to be
    # handled in the get_density_of_states function.
    cvs = []
    weighted_density = []
    bins = list(np.array(np.round(potential / energy_spacing), dtype=int))
    for k, structure in zip(bins, trajectory):
        cvs.append(cluster_space.get_cluster_vector(structure))
        weighted_density.append(df_density.density[k] / bins.count(k))

    # compute mean and standard deviation (std) of temperature weighted
    # cluster vector
    averages = []
    enref = np.min(potential)
    for temperature in temperatures:
        boltz = np.exp(-(potential - enref) / temperature / boltzmann_constant)
        sumint = np.sum(weighted_density * boltz)
        cv_mean = np.array([
            np.sum(weighted_density * boltz * cv) / sumint
            for cv in np.transpose(cvs)
        ])
        cv_std = np.array([
            np.sum(weighted_density * boltz * cv**2) / sumint
            for cv in np.transpose(cvs)
        ])
        cv_std = np.sqrt(cv_std - cv_mean**2)
        record = {
            'temperature': temperature,
            'cv_mean': cv_mean,
            'cv_std': cv_std
        }
        averages.append(record)

    return DataFrame.from_dict(averages)