コード例 #1
0
ファイル: test_adsorption.py プロジェクト: squiton/pymatgen
    def test_adsorb_both_surfaces(self):

        # Test out for monatomic adsorption
        o = Molecule("O", [[0, 0, 0]])
        adslabs = self.asf_100.adsorb_both_surfaces(o)
        adslabs_one = self.asf_100.generate_adsorption_structures(o)
        self.assertEqual(len(adslabs), len(adslabs_one))
        for adslab in adslabs:
            sg = SpacegroupAnalyzer(adslab)
            sites = sorted(adslab, key=lambda site: site.frac_coords[2])
            self.assertTrue(sites[0].species_string == "O")
            self.assertTrue(sites[-1].species_string == "O")
            self.assertTrue(sg.is_laue())

        # Test out for molecular adsorption
        oh = Molecule(["O", "H"], [[0, 0, 0], [0, 0, 1]])
        adslabs = self.asf_100.adsorb_both_surfaces(oh)
        adslabs_one = self.asf_100.generate_adsorption_structures(oh)
        self.assertEqual(len(adslabs), len(adslabs_one))
        for adslab in adslabs:
            sg = SpacegroupAnalyzer(adslab)
            sites = sorted(adslab, key=lambda site: site.frac_coords[2])
            self.assertTrue(sites[0].species_string in ["O", "H"])
            self.assertTrue(sites[-1].species_string in ["O", "H"])
            self.assertTrue(sg.is_laue())
コード例 #2
0
ファイル: test_adsorption.py プロジェクト: ExpHP/pymatgen
    def test_adsorb_both_surfaces(self):

        # Test out for monatomic adsorption
        o = Molecule("O", [[0, 0, 0]])
        adslabs = self.asf_100.adsorb_both_surfaces(o)
        adslabs_one = self.asf_100.generate_adsorption_structures(o)
        self.assertEqual(len(adslabs), len(adslabs_one))
        for adslab in adslabs:
            sg = SpacegroupAnalyzer(adslab)
            sites = sorted(adslab, key=lambda site: site.frac_coords[2])
            self.assertTrue(sites[0].species_string == "O")
            self.assertTrue(sites[-1].species_string == "O")
            self.assertTrue(sg.is_laue())

        # Test out for molecular adsorption
        oh = Molecule(["O", "H"], [[0, 0, 0], [0, 0, 1]])
        adslabs = self.asf_100.adsorb_both_surfaces(oh)
        adslabs_one = self.asf_100.generate_adsorption_structures(oh)
        self.assertEqual(len(adslabs), len(adslabs_one))
        for adslab in adslabs:
            sg = SpacegroupAnalyzer(adslab)
            sites = sorted(adslab, key=lambda site: site.frac_coords[2])
            self.assertTrue(sites[0].species_string in ["O", "H"])
            self.assertTrue(sites[-1].species_string in ["O", "H"])
            self.assertTrue(sg.is_laue())
コード例 #3
0
ファイル: interface.py プロジェクト: fxdirection35/pymatgen
    def combine_slabs(self):
        """
        Combine the slabs generated by get_oriented_slabs into interfaces
        """

        all_substrate_variants = []
        sub_labels = []
        for i, slab in enumerate(self.modified_substrate_structures):
            all_substrate_variants.append(slab)
            sub_labels.append(str(i))
            sg = SpacegroupAnalyzer(slab, symprec=1e-3)
            if not sg.is_laue():
                mirrored_slab = slab.copy()
                reflection_z = SymmOp.from_rotation_and_translation(
                    ((1, 0, 0), (0, 1, 0), (0, 0, -1)), (0, 0, 0))
                mirrored_slab.apply_operation(reflection_z, fractional=True)
                translation = [0, 0, -min(mirrored_slab.frac_coords[:, 2])]
                mirrored_slab.translate_sites(range(mirrored_slab.num_sites),
                                              translation)
                all_substrate_variants.append(mirrored_slab)
                sub_labels.append('%dm' % i)

        all_film_variants = []
        film_labels = []
        for i, slab in enumerate(self.modified_film_structures):
            all_film_variants.append(slab)
            film_labels.append(str(i))
            sg = SpacegroupAnalyzer(slab, symprec=1e-3)
            if not sg.is_laue():
                mirrored_slab = slab.copy()
                reflection_z = SymmOp.from_rotation_and_translation(
                    ((1, 0, 0), (0, 1, 0), (0, 0, -1)), (0, 0, 0))
                mirrored_slab.apply_operation(reflection_z, fractional=True)
                translation = [0, 0, -min(mirrored_slab.frac_coords[:, 2])]
                mirrored_slab.translate_sites(range(mirrored_slab.num_sites),
                                              translation)
                all_film_variants.append(mirrored_slab)
                film_labels.append('%dm' % i)

        # substrate first index, film second index
        self.interfaces = []
        self.interface_labels = []
        # self.interfaces = [[None for j in range(len(all_film_variants))] for i in range(len(all_substrate_variants))]
        for i, substrate in enumerate(all_substrate_variants):
            for j, film in enumerate(all_film_variants):
                self.interfaces.append(self.make_interface(substrate, film))
                self.interface_labels.append('%s/%s' %
                                             (film_labels[j], sub_labels[i]))
コード例 #4
0
    def nonstoichiometric_symmetrized_slab(self, slab, tol=1e-3):

        """
        This method checks whether or not the two surfaces of the slab are
        equivalent. If the point group of the slab has an inversion symmetry (
        ie. belong to one of the Laue groups), then it is assumed that the
        surfaces should be equivalent. Otherwise, sites at the bottom of the
        slab will be removed until the slab is symmetric. Note the removal of sites
        can destroy the stoichiometry of the slab. For non-elemental
        structures, the chemical potential will be needed to calculate surface energy.

        Arg:
            slab (Structure): A single slab structure
            tol (float): Tolerance for SpaceGroupanalyzer.

        Returns:
            Slab (structure): A symmetrized Slab object.
        """

        sg = SpacegroupAnalyzer(slab, symprec=tol)

        if sg.is_laue():
            return slab
        else:
            asym = True

            while asym or (len(slab) < len(self.parent)):

                # Keep removing sites from the bottom one by one until both
                # surfaces are symmetric or the number of sites removed has
                # exceeded 10 percent of the original slab

                c_dir = [site[2] for i, site in enumerate(slab.frac_coords)]

                slab.remove_sites([c_dir.index(min(c_dir))])

                # Check if the altered surface is symmetric

                sg = SpacegroupAnalyzer(slab, symprec=tol)

                if sg.is_laue():
                    asym = False

        if len(slab) < len(self.parent):
            warnings.warn("Too many sites removed, please use a larger slab "
                          "size.")

        return slab
コード例 #5
0
    def test_get_symmetric_sites(self):

        # Check to see if we get an equivalent site on one
        # surface if we add a new site to the other surface

        all_Ti_slabs = generate_all_slabs(self.ti,
                                          2,
                                          10,
                                          10,
                                          bonds=None,
                                          tol=1e-3,
                                          max_broken_bonds=0,
                                          lll_reduce=False,
                                          center_slab=False,
                                          primitive=True,
                                          max_normal_search=2,
                                          symmetrize=True)

        for slab in all_Ti_slabs:
            sorted_sites = sorted(slab, key=lambda site: site.frac_coords[2])
            site = sorted_sites[-1]
            point = site.frac_coords
            point[2] = point[2] + 0.1
            point2 = slab.get_symmetric_site(point)
            slab.append("O", point)
            slab.append("O", point2)

            # Check if slab is all symmetric
            sg = SpacegroupAnalyzer(slab)
            self.assertTrue(sg.is_laue())
コード例 #6
0
ファイル: test_surface.py プロジェクト: KhanWhale/pymatgen
    def test_symmetrization(self):

        # Restricted to primitive_elemental materials due to the risk of
        # broken stoichiometry. For compound materials, use is_polar()

        # Get all slabs for P6/mmm Ti and Fm-3m Ag up to index of 2

        all_Ti_slabs = generate_all_slabs(
            self.ti,
            2,
            10,
            10,
            bonds=None,
            tol=1e-3,
            max_broken_bonds=0,
            lll_reduce=False,
            center_slab=False,
            primitive=True,
            max_normal_search=2,
            symmetrize=True,
        )

        all_Ag_fcc_slabs = generate_all_slabs(
            self.agfcc,
            2,
            10,
            10,
            bonds=None,
            tol=1e-3,
            max_broken_bonds=0,
            lll_reduce=False,
            center_slab=False,
            primitive=True,
            max_normal_search=2,
            symmetrize=True,
        )

        all_slabs = [all_Ti_slabs, all_Ag_fcc_slabs]

        for i, slabs in enumerate(all_slabs):

            assymetric_count = 0
            symmetric_count = 0

            for i, slab in enumerate(slabs):
                sg = SpacegroupAnalyzer(slab)

                # Check if a slab is symmetric
                if not sg.is_laue():
                    assymetric_count += 1
                else:
                    symmetric_count += 1

            # Check if slabs are all symmetric
            self.assertEqual(assymetric_count, 0)
            self.assertEqual(symmetric_count, len(slabs))
コード例 #7
0
    def is_symmetric(self, symprec=0.1):
        """
        Checks if slab is symmetric, i.e., contains inversion symmetry.

        Args:
            symprec (float): Symmetry precision used for SpaceGroup analyzer.

        Returns:
            (bool) Whether slab contains inversion symmetry.
        """

        sg = SpacegroupAnalyzer(self, symprec=symprec)
        return sg.is_laue()
コード例 #8
0
ファイル: symmetry.py プロジェクト: CompRhys/matminer
    def featurize(self, s):
        sga = SpacegroupAnalyzer(s)
        output = []

        if "spacegroup_num" in self.features:
            output.append(sga.get_space_group_number())

        if "crystal_system" in self.features:
            output.append(sga.get_crystal_system())

        if "crystal_system_int" in self.features:
            output.append(GlobalSymmetryFeatures.crystal_idx[
                              sga.get_crystal_system()])

        if "is_centrosymmetric" in self.features:
            output.append(sga.is_laue())

        return output
コード例 #9
0
ファイル: test_surface.py プロジェクト: gmatteo/pymatgen
    def test_symmetrization(self):

        # Restricted to primitive_elemental materials due to the risk of
        # broken stoichiometry. For compound materials, use is_polar()

        # Get all slabs for P6/mmm Ti and Fm-3m Ag up to index of 2

        all_Ti_slabs = generate_all_slabs(self.ti, 2, 10, 10, bonds=None,
                                          tol=1e-3, max_broken_bonds=0,
                                          lll_reduce=False, center_slab=False,
                                          primitive=True, max_normal_search=2,
                                          symmetrize=True)

        all_Ag_fcc_slabs = generate_all_slabs(self.agfcc, 2, 10, 10, bonds=None,
                                              tol=1e-3, max_broken_bonds=0,
                                              lll_reduce=False,
                                              center_slab=False,
                                              primitive=True,
                                              max_normal_search=2,
                                              symmetrize=True)

        all_slabs = [all_Ti_slabs, all_Ag_fcc_slabs]

        for i, slabs in enumerate(all_slabs):

            assymetric_count = 0
            symmetric_count = 0

            for i, slab in enumerate(slabs):
                sg = SpacegroupAnalyzer(slab)

                # Check if a slab is symmetric
                if not sg.is_laue():
                    assymetric_count += 1
                else:
                    symmetric_count += 1

            # Check if slabs are all symmetric
            self.assertEqual(assymetric_count, 0)
            self.assertEqual(symmetric_count, len(slabs))
コード例 #10
0
ファイル: test_surface.py プロジェクト: gmatteo/pymatgen
    def test_get_symmetric_sites(self):

        # Check to see if we get an equivalent site on one
        # surface if we add a new site to the other surface

        all_Ti_slabs = generate_all_slabs(self.ti, 2, 10, 10, bonds=None,
                                          tol=1e-3, max_broken_bonds=0,
                                          lll_reduce=False, center_slab=False,
                                          primitive=True, max_normal_search=2,
                                          symmetrize=True)

        for slab in all_Ti_slabs:
            sorted_sites = sorted(slab, key=lambda site: site.frac_coords[2])
            site = sorted_sites[-1]
            point = np.array(site.frac_coords)
            point[2] = point[2] + 0.1
            point2 = slab.get_symmetric_site(point)
            slab.append("O", point)
            slab.append("O", point2)

            # Check if slab is all symmetric
            sg = SpacegroupAnalyzer(slab)
            self.assertTrue(sg.is_laue())
コード例 #11
0
ファイル: test_analyzer.py プロジェクト: zbwang/pymatgen
 def test_is_laue(self):
     s = Structure.from_spacegroup("Fm-3m",
                                   np.eye(3) * 3, ["Cu"], [[0, 0, 0]])
     a = SpacegroupAnalyzer(s)
     self.assertTrue(a.is_laue())
コード例 #12
0
ファイル: generation.py プロジェクト: SMTG-UCL/surfaxe
def generate_slabs(structure,
                   hkl,
                   thicknesses,
                   vacuums,
                   save_slabs=True,
                   save_metadata=True,
                   json_fname=None,
                   make_fols=False,
                   make_input_files=False,
                   max_size=500,
                   center_slab=True,
                   ox_states=None,
                   is_symmetric=True,
                   layers_to_relax=None,
                   fmt='poscar',
                   name='POSCAR',
                   config_dict=None,
                   user_incar_settings=None,
                   user_kpoints_settings=None,
                   user_potcar_settings=None,
                   parallelise=True,
                   **kwargs):
    """
    Generates all unique slabs for a specified Miller indices or up to a maximum 
    Miller index with minimum slab and vacuum thicknesses. It includes all 
    combinations for multiple zero dipole symmetric terminations for 
    the same Miller index. 
    
    The function returns None by default and generates either: 

    (i) POSCAR_hkl_slab_vac_index.vasp (default) 
    (ii) hkl/slab_vac_index folders with structure files
    (iii) hkl/slab_vac_index with all VASP input files 
    
    Or if `save_slabs=False` a list of dicts of all unique slabs is returned. 
    
    Args:
        structure (`str` or pmg Structure obj): Filename of structure file in 
            any format supported by pymatgen or pymatgen structure object. 
        hkl (`tuple`, `list` or `int`): Miller index as tuple, a list of Miller 
            indices or a maximum index up to which the search should be 
            performed. E.g. if searching for slabs up to (2,2,2) ``hkl=2``
        thicknesses (`list`): The minimum size of the slab in Angstroms. 
        vacuums (`list`): The minimum size of the vacuum in Angstroms.
        save_slabs (`bool`, optional): Whether to save the slabs to file. 
            Defaults to ``True``.
        save_metadata (`bool`, optional): Whether to save the slabs' metadata to 
            file. Saves the entire slab object to a json file 
            Defaults to ``True``. 
        json_fname (`str`, optional): Filename of json metadata file. Defaults to
            bulk_formula_metadata.json
        make_fols (`bool`, optional): Makes folders for each termination 
            and slab/vacuum thickness combinations containing structure files. 
            
            * ``True``: A Miller index folder is created, in which folders 
              named slab_vac_index are created to which the relevant structure 
              files are saved. 
                    
                    E.g. for a (0,0,1) slab of index 1 with a slab thickness of 
                    20 Å and vacuum thickness of 30 Å the folder structure would 
                    be: ``001/20_30_1/POSCAR``  

            * ``False``: The indexed structure files are put in a folder named  
              after the bulk formula. 
              
                    E.g. for a (0,0,1) MgO slab of index 1 with a slab thickness 
                    of 20 Å and vacuum thickness of 30 Å the folder structure 
                    would be: ``MgO/POSCAR_001_20_30_1``

            Defaults to ``False``.    
        make_input_files (`bool`, optional): Makes INCAR, POTCAR and 
            KPOINTS files in each folder. If ``make_input_files`` is ``True`` 
            but ``make_files`` or ``save_slabs`` is ``False``, files will be 
            saved to folders regardless. This only works with VASP input files, 
            other formats are not yet supported. Defaults to ``False``. 
        max_size (`int`, optional): The maximum number of atoms in the slab 
            specified to raise warning about slab size. Even if the warning is 
            raised, it still outputs the slabs regardless. Defaults to ``500``. 
        center_slab (`bool`, optional): The position of the slab in the 
            simulation cell. 
            
            * ``True``: the slab is centered with equal amounts of 
              vacuum above and below.

            * ``False``: the slab is at the bottom of the simulation cell with
              all of the vacuum on top of it. 

            Defaults to True. 

        ox_states (``None``, `list` or  `dict`, optional): Add oxidation states 
            to the bulk structure. Different types of oxidation states specified 
            will result in different pymatgen functions used. The options are: 
            
            * if supplied as ``list``: The oxidation states are added by site 
                    
                    e.g. ``[3, 2, 2, 1, -2, -2, -2, -2]``
            
            * if supplied as ``dict``: The oxidation states are added by element
                    
                    e.g. ``{'Fe': 3, 'O':-2}``
            
            * if ``None``: The oxidation states are added by guess. 
              
            Defaults to ``None``. 
        is_symmetric (`bool`, optional): Whether the slabs cleaved should 
            have inversion symmetry. If bulk is non-centrosymmetric, 
            ``is_symmetric`` needs to be ``False`` - the function will return no
            slabs as it looks for inversion symmetry. Take care checking the 
            slabs for mirror plane symmetry before just using them. Defaults to 
            ``True``. 
        layers_to_relax (`int`, optional): Specifies the number of layers at the 
            top and bottom of the slab that should be relaxed, keeps the centre
            constrained using selective dynamics. NB only works for VASP files 
        fmt (`str`, optional): The format of the output structure files. Options 
            include 'cif', 'poscar', 'cssr', 'json', not case sensitive. 
            Defaults to 'poscar'. 
        name (`str`, optional): The name of the surface slab structure file 
            created. Case sensitive. Defaults to 'POSCAR'
        config_dict (`dict` or `str`, optional): Specifies the dictionary used 
            for the generation of the input files. Suppports already loaded 
            dictionaires, yaml and json files. Surfaxe-supplied dictionaries 
            are PBE (``pe``), PBEsol (``ps``) and HSE06 (``hse06``) for single 
            shot calculations and PBE (``pe_relax``) and PBEsol (``ps_relax``) 
            for relaxations. Not case sensitive. Defaults to PBEsol (``ps``). 
        user_incar_settings (`dict`, optional): Overrides the default INCAR 
            parameter settings. Defaults to ``None``.
        user_kpoints_settings (`dict` or Kpoints object, optional): 
            Overrides the default kpoints settings. If it is supplied  
            as `dict`, it should be as ``{'reciprocal_density': 100}``. Defaults 
            to ``None``.
        user_potcar_settings (`dict`, optional): Overrides the default POTCAR 
            settings. Defaults to ``None``.
        parallelise (`bool`, optional): Use multiprocessing to generate
            slabs. Defaults to ``True``. 

    Returns:
        None (default) 
        or unique_slabs (list of dicts) 
    """

    # Set up additional arguments for multiprocessing and saving slabs
    mp_kwargs = {
        'in_unit_planes': False,
        'primitive': True,
        'max_normal_search': None,
        'reorient_lattice': True,
        'lll_reduce': True,
        'ftol': 0.1,
        'tol': 0.1,
        'max_broken_bonds': 0,
        'symmetrize': False,
        'repair': False,
        'bonds': None
    }
    mp_kwargs.update((k, kwargs[k]) for k in mp_kwargs.keys() & kwargs.keys())

    save_slabs_kwargs = {
        'user_incar_settings': None,
        'user_kpoints_settings': None,
        'user_potcar_settings': None,
        'constrain_total_magmom': False,
        'sort_structure': True,
        'potcar_functional': None,
        'user_potcar_functional': None,
        'force_gamma': False,
        'reduce_structure': None,
        'vdw': None,
        'use_structure_charge': False,
        'standardize': False,
        'sym_prec': 0.1,
        'international_monoclinic': True
    }
    save_slabs_kwargs.update(
        (k, kwargs[k]) for k in save_slabs_kwargs.keys() & kwargs.keys())
    save_slabs_kwargs.update({
        'user_incar_settings': user_incar_settings,
        'user_kpoints_settings': user_kpoints_settings,
        'user_potcar_settings': user_potcar_settings
    })

    # Import bulk relaxed structure, add oxidation states for slab dipole
    # calculations
    struc = _instantiate_structure(structure)

    # Check structure is conventional standard and warn if not
    sga = SpacegroupAnalyzer(struc)
    cs = sga.get_conventional_standard_structure()
    if cs.lattice != struc.lattice:
        warnings.formatwarning = _custom_formatwarning
        warnings.warn(
            'Lattice of the structure provided does not match the '
            'conventional standard structure. Miller indices are lattice dependent,'
            ' make sure you are using the correct bulk structure ')

    # Check if oxidation states were added to the bulk already
    struc = oxidation_states(struc, ox_states)

    # Check if hkl provided as tuple or int, find all available hkl if
    # provided as int; make into a list to iterate over
    if type(hkl) == tuple:
        miller = [hkl]
    elif type(hkl) == int:
        miller = get_symmetrically_distinct_miller_indices(struc, hkl)
    elif type(hkl) == list and all(isinstance(x, tuple) for x in hkl):
        miller = hkl
    else:
        raise TypeError(
            'Miller index should be supplied as tuple, int or list '
            'of tuples')

    # create all combinations of hkl, slab and vacuum thicknesses
    combos = itertools.product(miller, thicknesses, vacuums)

    # Check if bulk structure is noncentrosymmetric if is_symmetric=True,
    # change to False if not to make sure slabs are produced, issues warning
    if is_symmetric:
        sg = SpacegroupAnalyzer(struc)
        if not sg.is_laue():
            is_symmetric = False
            warnings.formatwarning = _custom_formatwarning
            warnings.warn(
                ('Inversion symmetry was not found in the bulk '
                 'structure, slabs produced will be non-centrosymmetric'))

    # Check if multiple cores are available, then iterate through the slab and
    # vacuum thicknesses and get all non polar symmetric slabs
    if multiprocessing.cpu_count() > 1 and parallelise == True:
        with multiprocessing.Pool() as pool:
            nested_provisional = pool.starmap(
                functools.partial(_mp_generate_slabs,
                                  struc,
                                  is_symmetric=is_symmetric,
                                  center_slab=center_slab,
                                  **mp_kwargs), combos)

        provisional = list(itertools.chain.from_iterable(nested_provisional))

    else:
        # Set up kwargs again
        SG_kwargs = {
            k: mp_kwargs[k]
            for k in [
                'in_unit_planes', 'primitive'
                'max_normal_search', 'reorient_lattice', 'lll_reduce'
            ]
        }
        gs_kwargs = {
            k: mp_kwargs[k]
            for k in [
                'ftol', 'tol', 'max_broken_bonds', 'symmetrize', 'repair',
                'bonds'
            ]
        }

        provisional = []
        for hkl, thickness, vacuum in combos:
            slabgen = SlabGenerator(struc,
                                    hkl,
                                    thickness,
                                    vacuum,
                                    center_slab=center_slab,
                                    **SG_kwargs)

            # Get the number of layers in the slab
            h = slabgen._proj_height
            p = round(h / slabgen.parent.lattice.d_hkl(slabgen.miller_index),
                      8)
            if slabgen.in_unit_planes:
                nlayers_slab = int(math.ceil(slabgen.min_slab_size / p))
            else:
                nlayers_slab = int(math.ceil(slabgen.min_slab_size / h))

            slabs = slabgen.get_slabs(**gs_kwargs)
            for i, slab in enumerate(slabs):
                # Get all the zero-dipole slabs with inversion symmetry
                if is_symmetric:
                    if slab.is_symmetric() and not slab.is_polar():
                        provisional.append({
                            'hkl':
                            ''.join(map(str, slab.miller_index)),
                            'slab_thickness':
                            thickness,
                            'slab_layers':
                            nlayers_slab,
                            'vac_thickness':
                            vacuum,
                            'slab_index':
                            i,
                            'slab':
                            slab
                        })

                # Get all the zero-dipole slabs wihtout inversion symmetry
                else:
                    if not slab.is_polar():
                        provisional.append({
                            'hkl':
                            ''.join(map(str, slab.miller_index)),
                            'slab_thickness':
                            thickness,
                            'slab_layers':
                            nlayers_slab,
                            'vac_thickness':
                            vacuum,
                            'slab_index':
                            i,
                            'slab':
                            slab
                        })

    # Iterate though provisional slabs to extract the unique slabs
    unique_list_of_dicts, repeat, large = _filter_slabs(provisional, max_size)

    if layers_to_relax is not None and fmt.lower() == 'poscar':
        unique_list_of_dicts, small = _get_selective_dynamics(
            struc, unique_list_of_dicts, layers_to_relax)

        if small:
            warnings.formatwarning = _custom_formatwarning
            warnings.warn(
                'Some slabs were too thin to fix the centre of the slab.'
                ' Slabs with no selective dynamics applied are: ' +
                ', '.join(map(str, small)))

    # Warnings for too large, too small, repeated and no slabs;
    if repeat:
        warnings.formatwarning = _custom_formatwarning
        warnings.warn('Not all combinations of hkl or slab/vac thicknesses '
                      'were generated because of repeat structures. '
                      'The repeat slabs are: ' + ', '.join(map(str, repeat)))

    if large:
        warnings.formatwarning = _custom_formatwarning
        warnings.warn('Some generated slabs exceed the max size specified.'
                      ' Slabs that exceed the max size are: ' +
                      ', '.join(map(str, large)))

    if len(unique_list_of_dicts) == 0:
        raise ValueError(
            'No zero dipole slabs found for specified Miller index')

    # Save the metadata or slabs to file or return the list of dicts
    if save_metadata:
        bulk_name = struc.composition.reduced_formula
        if json_fname is None:
            json_fname = '{}_metadata.json'.format(bulk_name)
        unique_list_of_dicts_copy = deepcopy(unique_list_of_dicts)
        for i in unique_list_of_dicts_copy:
            i['slab'] = i['slab'].as_dict()
        with open(json_fname, 'w') as f:
            json.dump(unique_list_of_dicts_copy, f)

    if save_slabs:
        slabs_to_file(list_of_slabs=unique_list_of_dicts,
                      structure=struc,
                      make_fols=make_fols,
                      make_input_files=make_input_files,
                      config_dict=config_dict,
                      fmt=fmt,
                      name=name,
                      **save_slabs_kwargs)

    else:
        return unique_list_of_dicts
コード例 #13
0
    def process_item(self, item):
        """
        Process the tasks and materials into a dielectrics collection

        Args:
            item dict: a dict of material_id, structure, and tasks

        Returns:
            dict: a dieletrics dictionary  
        """
        def poly(matrix):
            diags = np.diagonal(matrix)
            return np.prod(diags) / np.sum(
                np.prod(comb) for comb in combinations(diags, 2))

        d = {self.dielectric.key: item[self.materials.key]}

        structure = Structure.from_dict(item["structure"])

        if item.get("dielectric", False):
            ionic = Tensor(
                item["dielectric"]["ionic"]).symmetrized.fit_to_structure(
                    structure).convert_to_ieee(structure)
            static = Tensor(
                item["dielectric"]["static"]).symmetrized.fit_to_structure(
                    structure).convert_to_ieee(structure)
            total = ionic + static

            d["dielectric"] = {
                "total": total,
                "ionic": ionic,
                "static": static,
                "e_total": poly(total),
                "e_ionic": poly(ionic),
                "e_static": poly(static)
            }

        sga = SpacegroupAnalyzer(structure)
        # Update piezo if non_centrosymmetric
        if item.get("piezo", False) and not sga.is_laue():
            static = PiezoTensor.from_voigt(np.array(
                item['piezo']["static"])).symmetrized.fit_to_structure(
                    structure).convert_to_ieee(structure).voigt
            ionic = PiezoTensor.from_voigt(np.array(
                item['piezo']["ionic"])).symmetrized.fit_to_structure(
                    structure).convert_to_ieee(structure).voigt
            total = ionic + static

            directions, charges, strains = np.linalg.svd(total)

            max_index = np.argmax(np.abs(charges))
            d["piezo"] = {
                "total": total,
                "ionic": ionic,
                "static": static,
                "e_ij_max": charges[max_index],
                "max_direction": directions[max_index],
                "strain_for_max": strains[max_index]
            }

        if len(d) > 1:
            return d

        return None
コード例 #14
0
    def calc(self, item):
        """
        Process the tasks and materials into a dielectrics collection

        Args:
            item dict: a dict of material_id, structure, and tasks

        Returns:
            dict: a dieletrics dictionary
        """
        def poly(matrix):
            diags = np.diagonal(matrix)
            return np.prod(diags) / np.sum(
                np.prod(comb) for comb in combinations(diags, 2))

        if item["bandstructure"]["band_gap"] > 0:

            structure = Structure.from_dict(
                item.get("dielectric", {}).get("structure", None))

            ionic = Tensor(
                item["dielectric"]["ionic"]).convert_to_ieee(structure)
            static = Tensor(
                item["dielectric"]["static"]).convert_to_ieee(structure)
            total = ionic + static

            d = {
                "dielectric": {
                    "total": total,
                    "ionic": ionic,
                    "static": static,
                    "e_total": np.average(np.diagonal(total)),
                    "e_ionic": np.average(np.diagonal(ionic)),
                    "e_static": np.average(np.diagonal(static)),
                    "n": np.sqrt(np.average(np.diagonal(static))),
                }
            }

            sga = SpacegroupAnalyzer(structure)
            # Update piezo if non_centrosymmetric
            if item.get("piezo", False) and not sga.is_laue():
                static = PiezoTensor.from_voigt(
                    np.array(item["piezo"]["static"]))
                ionic = PiezoTensor.from_voigt(np.array(
                    item["piezo"]["ionic"]))
                total = ionic + static

                # Symmeterize Convert to IEEE orientation
                total = total.convert_to_ieee(structure)
                ionic = ionic.convert_to_ieee(structure)
                static = static.convert_to_ieee(structure)

                directions, charges, strains = np.linalg.svd(
                    total.voigt, full_matrices=False)

                max_index = np.argmax(np.abs(charges))

                max_direction = directions[max_index]

                # Allow a max miller index of 10
                min_val = np.abs(max_direction)
                min_val = min_val[min_val > (np.max(min_val) /
                                             self.max_miller)]
                min_val = np.min(min_val)

                d["piezo"] = {
                    "total": total.zeroed().voigt,
                    "ionic": ionic.zeroed().voigt,
                    "static": static.zeroed().voigt,
                    "e_ij_max": charges[max_index],
                    "max_direction": np.round(max_direction / min_val),
                    "strain_for_max": strains[max_index],
                }
        else:
            d = {
                "dielectric": {},
                "_warnings": [
                    "Dielectric calculated for likely metal. Values are unlikely to be converged"
                ],
            }

            if item.get("piezo", False):
                d.update({
                    "piezo": {},
                    "_warnings": [
                        "Piezoelectric calculated for likely metal. Values are unlikely to be converged"
                    ],
                })

        return d
コード例 #15
0
ファイル: test_analyzer.py プロジェクト: matk86/pymatgen
 def test_is_laue(self):
     s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"],
                                   [[0, 0, 0]])
     a = SpacegroupAnalyzer(s)
     self.assertTrue(a.is_laue())