Example #1
0
    def build_supercell_full_disorder(pstructure, scaling_matrix):
        """
        get a supercell with all disordered sites inside, should be used to generate a certain config based on instruction

        :param pstructure:
        :param scaling_matrix:
        :return:
        """
        scale_matrix = np.array(scaling_matrix, np.int16)
        if scale_matrix.shape != (3, 3):
            scale_matrix = np.array(scale_matrix * np.eye(3), np.int16)
        new_lattice = Lattice(np.dot(scale_matrix, pstructure._lattice.matrix))
        f_lat = lattice_points_in_supercell(scale_matrix)
        c_lat = new_lattice.get_cartesian_coords(f_lat)
        new_sites = []
        for site in pstructure.sites:
            icell = 0
            for v in c_lat:
                site_properties = deepcopy(site.properties)
                site_properties['icell'] = icell
                s = PeriodicSite(site.species,
                                 site.coords + v,
                                 new_lattice,
                                 properties=site_properties,
                                 coords_are_cartesian=True,
                                 to_unit_cell=False)
                new_sites.append(s)
                icell += 1
        new_charge = pstructure._charge * np.linalg.det(
            scale_matrix) if pstructure._charge else None
        return Structure.from_sites(new_sites, charge=new_charge), len(c_lat)
Example #2
0
    def __getitem__(self, frames):
        """
        Gets a subset of the trajectory if a slice is given, if an int is given, return a structure

        Args:
            frames (int, slice): int or slice of trajectory to return

        Return:
            (Trajectory, Structure) Subset of trajectory
        """
        if isinstance(frames, int) and frames < self.frac_coords.shape[0]:
            lattice = self.lattice if self.constant_lattice else self.lattice[frames]
            site_properties = self.site_properties[frames] if self.site_properties else None
            return Structure(Lattice(lattice), self.species, self.frac_coords[frames], site_properties=site_properties,
                             to_unit_cell=True)

        if isinstance(frames, slice):
            frames = np.arange(frames.start, frames.stop, frames.step)
        elif not (isinstance(frames, list) or isinstance(frames, np.ndarray)):
            try:
                frames = np.asarray(frames)
            except:
                raise Exception('Given accessor is not of type int, slice, tuple, list, or array')

        if (isinstance(frames, list) or isinstance(frames, np.ndarray)) and \
                (np.asarray([frames]) < self.frac_coords.shape[0]).all():
            if self.constant_lattice:
                lattice = self.lattice
            else:
                lattice = self.lattice[frames, :]
            return Trajectory(lattice, self.species, self.frac_coords[frames, :], self.time_step,
                              self.site_properties)
        else:
            warnings.warn('Some or all selected frames exceed trajectory length')
        return
Example #3
0
    def apply_transformation(self, structure):
        """
        Returns a copy of structure with lattice parameters
        and sites scaled to the same degree as the relaxed_structure.

        Arg:
            structure (Structure): A structurally similar structure in
                regards to crystal and site positions.
        """

        if self.species_map is None:
            match = StructureMatcher()
            s_map = match.get_best_electronegativity_anonymous_mapping(self.unrelaxed_structure, structure)
        else:
            s_map = self.species_map

        params = list(structure.lattice.abc)
        params.extend(structure.lattice.angles)
        new_lattice = Lattice.from_parameters(*(p * self.params_percent_change[i] for i, p in enumerate(params)))
        species, frac_coords = [], []
        for site in self.relaxed_structure:
            species.append(s_map[site.specie])
            frac_coords.append(site.frac_coords)

        return Structure(new_lattice, species, frac_coords)
def generate_Si_cluster():
    from pymatgen.io.xyz import XYZ

    coords = [[0, 0, 0], [0.75, 0.5, 0.75]]
    lattice = Lattice.from_parameters(a=3.84, b=3.84, c=3.84, alpha=120, beta=90, gamma=60)

    struct = Structure(lattice, ['Si', 'Si'], coords)
    struct.make_supercell([2, 2, 2])

    # Creating molecule for testing
    mol = Molecule.from_sites(struct)
    XYZ(mol).write_file(os.path.join(test_dir, "Si_cluster.xyz"))

    # Rorate the whole molecule
    mol_rotated = mol.copy()
    rotate(mol_rotated, seed=42)
    XYZ(mol_rotated).write_file(os.path.join(test_dir, "Si_cluster_rotated.xyz"))

    # Perturbing the atom positions
    mol_perturbed = mol.copy()
    perturb(mol_perturbed, 0.3, seed=42)
    XYZ(mol_perturbed).write_file(os.path.join(test_dir, "Si_cluster_perturbed.xyz"))

    # Permuting the order of the atoms
    mol_permuted = mol.copy()
    permute(mol_permuted, seed=42)
    XYZ(mol_permuted).write_file(os.path.join(test_dir, "Si_cluster_permuted.xyz"))

    # All-in-one
    mol2 = mol.copy()
    rotate(mol2, seed=42)
    perturb(mol2, 0.3, seed=42)
    permute(mol2, seed=42)
    XYZ(mol2).write_file(os.path.join(test_dir, "Si_cluster_2.xyz"))
Example #5
0
def get_modeldimers_array(bones: [ModelBone], lattice: Lattice, maxfold=2):
    """
    :param maxfold: translation vector in fc can be [h, h, h] where maxfold <= h <= maxfold
    :return: dimers_array, z x z x n array, dimers[i][j][k] is the dimer of omols[i], omols[j] with translation vector as transv_fcs[k]
             transv_fcs
    """
    z = len(bones)
    transv_1d = list(range(-maxfold, maxfold + 1))
    transv_fcs = np.array(np.meshgrid(transv_1d, transv_1d, transv_1d)).T.reshape(-1, 3)
    # symmetry dimers[i][j][transv_fcs[k]] = dimers[j][i][-transv_fcs[k]]
    dimers = np.empty((z, z, len(transv_fcs)), dtype=ModelBoneDimer)
    used_transv_fcs = transv_fcs

    for i in range(z):
        ref = deepcopy(bones[i])
        for j in range(z):
            var = deepcopy(bones[j])
            for k in range(len(used_transv_fcs)):
                transv = lattice.get_cartesian_coords(used_transv_fcs[k])
                var_k: ModelBone = deepcopy(var)
                for h in range(len(var_k)):
                    var_k.pts[h] += transv
                dimer_ijk = ModelBoneDimer(ref, var_k, label="{}_{}_{}".format(i, j, k))
                dimers[i][j][k] = dimer_ijk
    return dimers, transv_fcs
    def apply_transformation(self, structure):
        """
        Returns a copy of structure with lattice parameters
        and sites scaled to the same degree as the relaxed_structure.

        Arg:
            structure (Structure): A structurally similar structure in
                regards to crystal and site positions.
        """

        if self.species_map == None:
            match = StructureMatcher()
            s_map = \
                match.get_best_electronegativity_anonymous_mapping(self.unrelaxed_structure,
                                                                   structure)
        else:
            s_map = self.species_map

        params = list(structure.lattice.abc)
        params.extend(structure.lattice.angles)
        new_lattice = Lattice.from_parameters(*[p*self.params_percent_change[i] \
                                                for i, p in enumerate(params)])
        species, frac_coords = [], []
        for site in self.relaxed_structure:
            species.append(s_map[site.specie])
            frac_coords.append(site.frac_coords)

        return Structure(new_lattice, species, frac_coords)
Example #7
0
    def delete_bt_layer(self, bt, tol=0.25, axis=2):
        """
        Delete bottom or top layer of the structure.
        Args:
            bt (str): Specify whether it's a top or bottom layer delete. "b"
                means bottom layer and "t" means top layer.
            tol (float), Angstrom: Tolerance factor to determine whether two
                atoms are at the same plane.
                Default to 0.25
            axis (int): The direction of top and bottom layers. 0: x, 1: y, 2: z

        """
        if bt == "t":
            l1, l2 = (-1, -2)
        else:
            l1, l2 = (0, 1)

        l = self.lattice.abc[axis]
        layers = self.sort_sites_in_layers(tol=tol, axis=axis)
        l_dist = abs(layers[l1][0].coords[axis] - layers[l2][0].coords[axis])
        l_vector = [1, 1]
        l_vector.insert(axis, (l - l_dist) / l)
        new_lat = Lattice(self.lattice.matrix * np.array(l_vector)[:, None])

        layers.pop(l1)
        sites = reduce(lambda x, y: np.concatenate((x, y), axis=0), layers)
        new_sites = []
        l_dist = 0 if bt == "t" else l_dist
        l_vector = [0, 0]
        l_vector.insert(axis, l_dist)
        for i in sites:
            new_sites.append(PeriodicSite(i.specie, i.coords - l_vector,
                                          new_lat, coords_are_cartesian=True))
        self._sites = new_sites
        self._lattice = new_lat
Example #8
0
 def setUp(self):
     self.si = Element("Si")
     coords = list()
     coords.append([0, 0, 0])
     coords.append([0.75, 0.5, 0.75])
     self.lattice = Lattice([[3.8401979337, 0.00, 0.00],
                             [1.9200989668, 3.3257101909, 0.00],
                             [0.00, -2.2171384943, 3.1355090603]])
     self.struct = Structure(self.lattice, [self.si, self.si], coords)
Example #9
0
 def test_properties(self):
     self.assertEquals(self.kpoint.frac_coords[0], 0.1)
     self.assertEquals(self.kpoint.frac_coords[1], 0.4)
     self.assertEquals(self.kpoint.frac_coords[2], -0.5)
     self.assertEquals(self.kpoint.a, 0.1)
     self.assertEquals(self.kpoint.b, 0.4)
     self.assertEquals(self.kpoint.c, -0.5)
     self.assertEquals(self.lattice, Lattice.cubic(10.0))
     self.assertEquals(self.kpoint.cart_coords[0], 1.0)
     self.assertEquals(self.kpoint.cart_coords[1], 4.0)
     self.assertEquals(self.kpoint.cart_coords[2], -5.0)
     self.assertEqual(self.kpoint.label, "X")
Example #10
0
    def setUp(self):
        l = Lattice([[3.52,0.0,2.033], [1.174,3.32,2.033], \
                [0.0,0.0,4.066]])
        s_bulk = Structure(l, ['Ga', 'As'], \
                [[0.0000, 0.0000, 0.0000], \
                [0.2500, 0.2500, 0.2500]])
        defect_site = PeriodicSite('As', [0.25, 0.25, 0.25], l)
        defect = Vacancy(s_bulk, defect_site, charge=1.)
        defect_entry = DefectEntry(defect, 0.)

        entries = [defect_entry]
        vbm = 0.2
        band_gap = 1.
        dpd = DefectPhaseDiagram(entries, vbm, band_gap)
        self.dp = DefectPlotter(dpd)
Example #11
0
    def get_dist_and_trans(lattice: Lattice, fc1, fc2):
        """
        get the shortest distance and corresponding translation vector between two frac coords

        :param lattice: pmg lattic obj
        :param fc1:
        :param fc2:
        :return:
        """
        v, d2 = pbc_shortest_vectors(lattice, fc1, fc2, return_d2=True)
        if len(np.array(fc1).shape) == 1:
            fc = lattice.get_fractional_coords(v[0][0]) + fc1 - fc2
        else:
            fc = np.zeros((len(fc1), len(fc2), 3))
            for i in range(len(fc1)):
                for j in range(len(fc2)):
                    fc_vector = np.dot(v[i][j], lattice.inv_matrix)
                    fc[i][j] = fc_vector + fc1[i] - fc2[j]
        return np.sqrt(d2), fc
Example #12
0
    def make_supercell(self, scaling_matrix):
        """
        Create a supercell. Very similar to pymatgen's Structure.make_supercell
        However, we need to make sure that all fractional coordinates that equal
        to 1 will become 0 and the lattice are redefined so that x_c = [0, 0, c]

        Args:
            scaling_matrix (3x3 matrix): The scaling matrix to make supercell.
        """
        s = self * scaling_matrix
        for i, site in enumerate(s):
            f_coords = np.mod(site.frac_coords, 1)
            # The following for loop is probably not necessary. But I will leave
            # it here for now.
            for j, v in enumerate(f_coords):
                if abs(v - 1) < 1e-6:
                    f_coords[j] = 0
            s[i] = PeriodicSite(site.specie, f_coords, site.lattice,
                                properties=site.properties)
        self._sites = s.sites
        self._lattice = s.lattice
        new_lat = Lattice.from_parameters(*s.lattice.parameters)
        self.lattice = new_lat
Example #13
0
    def __init__(self, cifstring: str):
        """
        this can only handle one alternative configuration for the asymmetric unit

        one asymmetric unit == inv_conf + disg1 + disg2

        disg1 = disunit_a + disunit_b + ...

        disg2 = disunit_a' + disunit_b' + ...

        DisorderPair_a = disunit_a + disunit_a'

        if the cif file contains previouly fitted occu and disg,
        we call it dis-0 and we use occu/disg info to get inv_conf, disg1, disg2

        if there is no previously fitted info, we deal with the following situations:

            dis-1:  set(self.tags) is ["", <non-word>, <word>, ...], EI<non-word> -- EI,

            note x17059.cif is dis-1 but it has hydrogens like H12A -- H12D, this can only be captured
            by previously fitted disg and occu,

            dis-2:  set(self.tags) is ["", <non-word>, <word>, ...], EI<non-word> -- E'I' e.g. ALOVOO.cif

            nodis-0: no dup in self.eis, set(self.tags) is {""}

            nodis-1: dup in self.eis, set(self.tags) is ["", <word>, ...], this could be a dis as in ASIXEH

            weird: else

        for dis-1, dis-2, we fill the occu, disg fields in cifdata, so they can be coonverted to dis-0

        Attributes:
            data[atomlabel] = [x, y, z, symbol, occu, disgrp] this will be used to write config cif file
        """
        # prepare_data into cifdata
        self.classification = None
        self.cifstring = cifstring
        self.identifier, self.cifdata = get_pmg_dict(self.cifstring)
        self.cifdata['_atom_site_fract_x'] = [
            braket2float(x) for x in self.cifdata['_atom_site_fract_x']
        ]
        self.cifdata['_atom_site_fract_y'] = [
            braket2float(x) for x in self.cifdata['_atom_site_fract_y']
        ]
        self.cifdata['_atom_site_fract_z'] = [
            braket2float(x) for x in self.cifdata['_atom_site_fract_z']
        ]

        for i in range(len(self.cifdata['_atom_site_type_symbol'])):
            if self.cifdata['_atom_site_type_symbol'][i] == 'D':
                warnings.warn(
                    'D is considered as H in the ciffile _atom_site_type_symbol!'
                )
                self.cifdata['_atom_site_type_symbol'][i] = 'H'

        # check cif file
        try:
            labels = self.cifdata['_atom_site_label']
        except KeyError:
            raise CifFileError('no _atom_site_label field in the cifstring!')
        if len(labels) != len(set(labels)):
            warnings.warn(
                'duplicate labels found in the cifstring, reassign labels!')
            for i in range(len(self.cifdata['_atom_site_label'])):
                label = AtomLabel(self.cifdata['_atom_site_label'][i])
                self.cifdata['_atom_site_label'][i] = label.element + str(
                    i) + label.tag
            # raise CifFileError('duplicate labels found in the cifstring!')

        # "global" info
        self.labels = [AtomLabel(lab) for lab in labels]
        self.eis = [al.ei for al in self.labels]
        self.tags = [al.tag for al in self.labels]
        self.latparams = [self.cifdata[k] for k in latt_labels]
        self.lattice = Lattice.from_parameters(
            *[braket2float(p) for p in self.latparams], True)

        if '_atom_site_disorder_group' in self.cifdata.keys():
            self.was_fitted = True

            # deal with e.g. k06071
            for i in range(len(self.cifdata['_atom_site_disorder_group'])):
                if self.cifdata['_atom_site_disorder_group'][i] != ".":
                    dv = self.cifdata['_atom_site_disorder_group'][i]
                    dv = abs(int(dv))
                    self.cifdata['_atom_site_disorder_group'][i] = dv

            disgs = self.cifdata['_atom_site_disorder_group']

            disg_vals = list(set([disg for disg in disgs if disg != "."]))
            disg_vals.sort()
            for i in range(len(self.cifdata['_atom_site_disorder_group'])):
                for j in range(len(disg_vals)):
                    dv = disg_vals[j]
                    if self.cifdata['_atom_site_disorder_group'][i] == dv:
                        self.cifdata['_atom_site_disorder_group'][i] = str(j +
                                                                           1)
                        break
            if '_atom_site_occupancy' not in self.cifdata.keys():
                occus = []
                for disg in self.cifdata['_atom_site_disorder_group']:
                    if disg == '.':
                        occus.append(1)
                    else:
                        if int(disg) & 1:
                            occus.append(0.51)
                        else:
                            occus.append(0.49)
                self.cifdata['_atom_site_occupancy'] = occus
        else:
            self.was_fitted = False

        if self.was_fitted:
            self.cifdata['_atom_site_occupancy'] = [
                braket2float(x) for x in self.cifdata['_atom_site_occupancy']
            ]
            # self.cifdata['_atom_site_disorder_group'] = [braket2float(x) for x in
            #                                              self.cifdata['_atom_site_disorder_group']]

        # prepare self.data to be used in parsing
        data = map(
            list,
            zip(
                self.cifdata['_atom_site_fract_x'],
                self.cifdata['_atom_site_fract_y'],
                self.cifdata['_atom_site_fract_z'],
                self.cifdata['_atom_site_type_symbol'],
            ))
        data = list(data)
        data = OrderedDict(zip(self.labels, data))
        self.data = data

        for i in range(len(self.labels)):
            al = self.labels[i]
            if self.was_fitted:
                self.data[al].append(self.cifdata['_atom_site_occupancy'][i])
                self.data[al].append(
                    self.cifdata['_atom_site_disorder_group'][i])
            else:
                self.data[al].append(None)
                self.data[al].append(None)
Example #14
0
    def __getitem__(self, frames):
        """
        Gets a subset of the trajectory if a slice is given, if an int is given, return a structure
        Args:
            frames (int, slice): int or slice of trajectory to return
        Return:
            (Trajectory, Structure) Subset of trajectory
        """
        # If trajectory is in displacement mode, return the displacements at that frame
        if self.coords_are_displacement:
            if isinstance(frames, int):
                if frames >= np.shape(self.frac_coords)[0]:
                    raise ValueError(
                        "Selected frame exceeds trajectory length")
                # For integer input, return the displacements at that timestep
                return self.frac_coords[frames]
            if isinstance(frames, slice):
                # For slice input, return a list of the displacements
                start, stop, step = frames.indices(len(self))
                return [self.frac_coords[i] for i in range(start, stop, step)]
            if isinstance(frames, (list, np.ndarray)):
                # For list input, return a list of the displacements
                pruned_frames = [
                    i for i in frames if i < len(self)
                ]  # Get rid of frames that exceed trajectory length
                if len(pruned_frames) < len(frames):
                    warnings.warn(
                        "Some or all selected frames exceed trajectory length")
                return [self.frac_coords[i] for i in pruned_frames]
            raise Exception(
                "Given accessor is not of type int, slice, list, or array")

        # If trajectory is in positions mode, return a structure for the given frame or trajectory for the given frames
        if isinstance(frames, int):
            if frames >= np.shape(self.frac_coords)[0]:
                raise ValueError("Selected frame exceeds trajectory length")
            # For integer input, return the structure at that timestep
            lattice = self.lattice if self.constant_lattice else self.lattice[
                frames]
            site_properties = (self.site_properties[frames]
                               if self.site_properties else None)
            site_properties = (self.site_properties[frames]
                               if self.site_properties else None)
            return Structure(
                Lattice(lattice),
                self.species,
                self.frac_coords[frames],
                site_properties=site_properties,
                to_unit_cell=True,
            )
        if isinstance(frames, slice):
            # For slice input, return a trajectory of the sliced time
            start, stop, step = frames.indices(len(self))
            pruned_frames = range(start, stop, step)
            lattice = (self.lattice if self.constant_lattice else
                       [self.lattice[i] for i in pruned_frames])
            frac_coords = [self.frac_coords[i] for i in pruned_frames]
            if self.site_properties is not None:
                site_properties = [
                    self.site_properties[i] for i in pruned_frames
                ]
            else:
                site_properties = None
            if self.frame_properties is not None:
                frame_properties = {}
                for key, item in self.frame_properties.items():
                    frame_properties[key] = [item[i] for i in pruned_frames]
            else:
                frame_properties = None
            return Trajectory(
                lattice,
                self.species,
                frac_coords,
                time_step=self.time_step,
                site_properties=site_properties,
                frame_properties=frame_properties,
                constant_lattice=self.constant_lattice,
                coords_are_displacement=False,
                base_positions=self.base_positions,
            )
        if isinstance(frames, (list, np.ndarray)):
            # For list input, return a trajectory of the specified times
            pruned_frames = [
                i for i in frames if i < len(self)
            ]  # Get rid of frames that exceed trajectory length
            if len(pruned_frames) < len(frames):
                warnings.warn(
                    "Some or all selected frames exceed trajectory length")
            lattice = (self.lattice if self.constant_lattice else
                       [self.lattice[i] for i in pruned_frames])
            frac_coords = [self.frac_coords[i] for i in pruned_frames]
            if self.site_properties is not None:
                site_properties = [
                    self.site_properties[i] for i in pruned_frames
                ]
            else:
                site_properties = None
            if self.frame_properties is not None:
                frame_properties = {}
                for key, item in self.frame_properties.items():
                    frame_properties[key] = [item[i] for i in pruned_frames]
            else:
                frame_properties = None
            return Trajectory(
                lattice,
                self.species,
                frac_coords,
                time_step=self.time_step,
                site_properties=site_properties,
                frame_properties=frame_properties,
                constant_lattice=self.constant_lattice,
                coords_are_displacement=False,
                base_positions=self.base_positions,
            )
        raise Exception(
            "Given accessor is not of type int, slice, tuple, list, or array")
Example #15
0
    crystal = Structure.from_file(
        filename=each_original_vasp)  # vasp file read -> structure 정보 접근

    for i in range(
            num_noised_files):  # original vasp file로부터 noised vasp 파일을 횟수만큼 생성

        # -------------------------- lattice 구조에 noise 부여하기 -----------------------------------------
        lattice_shell = np.zeros(
            shape=crystal.lattice.matrix.shape)  # 새로운 lattice matrix shell 생성

        noised_lattice = gaussian_noise_level * np.random.normal(
            0, 1, 9).reshape((3, 3))  # 기존 lattice matrix에 넣을 noise 생성

        new_lattice_matrix = crystal.lattice.matrix + noised_lattice  # 기존 lattice matrix에 noise 추가

        noised_lattice = Lattice(new_lattice_matrix)  # noise 추가된 새로운 lattice
        noised_crystal = Structure(
            noised_lattice, crystal.species,
            crystal.frac_coords)  # unitcell에 noise 추가된 결정구조
        # -----------------------------------------------------------------------------------------------

        # --------------------------- 결정구조 안의 각 원자에 대해 좌표 noise 부여 -------------------------
        for j in range(
                len(noised_crystal)):  # For each atom in the crystal structure
            noised_coord = list(gaussian_noise_level * np.random.normal(
                0, 1, 3).reshape(-1))  # internal coordinate noise
            noised_crystal[j] = noised_crystal[j].specie.name, noised_crystal[
                j].frac_coords + noised_coord  # 각 원자 좌표에 noise 추가
        # -----------------------------------------------------------------------------------------------

        # vasp file saved
Example #16
0
 def setUp(self):
     self.lattice = Lattice.cubic(10.0)
     self.kpoint = Kpoint([0.1, 0.4, -0.5], self.lattice, label = "X")
Example #17
0
 def get_orthogonal_grain(self):
     a, b, c = self.lattice.abc
     new_latt = Lattice.orthorhombic(a, b, c)
     return Structure(new_latt, self.species, self.frac_coords)