예제 #1
0
    def random_cell(composition):
        comp = Composition(composition)
        volume = comp.covalent_volume(packing='cubes')

        random.seed()

        # make 3 random lengths
        a = (1.0 + 0.5 * random.random())
        b = (1.0 + 0.5 * random.random())
        c = (1.0 + 0.5 * random.random())

        # now we make 3 random angles
        alpha = 60.0 + 60.0 * random.random()
        beta = 60.0 + 60.0 * random.random()
        gamma = 60.0 + 60.0 * random.random()

        lattice = Lattice().from_parameters_to_cell(a, b, c, alpha, beta,
                                                    gamma)

        factor = (volume / lattice.volume)**(1 / 3.0)
        lattice = Lattice().from_parameters_to_cell(factor * a, factor * b,
                                                    factor * c, alpha, beta,
                                                    gamma)
        lattice.align_with_axis()
        lattice.align_with_plane()

        return lattice
예제 #2
0
    def random_cell(composition):
        comp = Composition(composition)
        volume = comp.covalent_volume(packing='cubes')

        random.seed()

        # make 3 random lengths
        a = (1.0 + 0.5 * random.random())
        b = (1.0 + 0.5 * random.random())
        c = (1.0 + 0.5 * random.random())

        # now we make 3 random angles
        alpha = 60.0 + 60.0 * random.random()
        beta = 60.0 + 60.0 * random.random()
        gamma = 60.0 + 60.0 * random.random()

        lattice = Lattice().from_parameters_to_cell(a, b, c, alpha, beta, gamma)

        factor = (volume / lattice.volume) ** (1 / 3.0)
        lattice = Lattice().from_parameters_to_cell(factor * a, factor * b, factor * c, alpha, beta, gamma)
        lattice.align_with_axis()
        lattice.align_with_plane()

        return lattice
예제 #3
0
    def get_composition(self, gcd=True):
        """
        Computes the composition of the Structure
        as the count of each species in the cell
        If gcd is True the values are divided by the
        greatest common divisor

        :param gcd: bool

        :rtype : Composition
        """
        if self._composition is None:
            species = {}
            for atom in self.symbols:
                if atom in species:
                    species[atom] += 1
                else:
                    species[atom] = 1
            self._composition = Composition(species)
        return self._composition
예제 #4
0
 def testraise(self):
     """
     Test exceptions in Composition                               :
     """
     a = Composition('H2O')
     self.assertRaises(ValueError, a.covalent_volume, 'torus')
예제 #5
0
    def random_cell(composition, method='stretching', stabilization_number=20, nparal=5, periodic=True):
        """
        Generate a random cell
        There are two algorithms implemented:

        scaling: Generate a random cell and random distribution of atoms and
                scale the lattice to separate the atoms.

        stretching: Generating a random cell and random distribution of atoms
                    and stretching their bonds until the distance between any
                    two atoms is always greater than the sum of covalent radius.

        :param composition: (pychemia.Composition)
        :param method: (str)
        :param stabilization_number: (int)
        :param nparal: (int)
        :param periodic: (bool)
        :return:

        Examples:
        >>> import pychemia
        >>> import os
        >>> st = pychemia.Structure.random_cell('LiAlCl4', stabilization_number=3)
        >>> st.natom
        6
        >>> st.save_json('test.json')
        >>> st2 = pychemia.Structure.load_json('test.json')
        >>> st == st2
        True
        >>> os.remove('test.json')
        """
        comp = Composition(composition)
        pcm_log.debug('Generating a random structure with composition: ' + str(comp.composition))
        natom = comp.natom
        symbols = comp.symbols

        best_volume = sys.float_info.max
        best_volume = float('inf')
        best_structure = None
        optimal_volume = comp.covalent_volume('cubes')
        stabilization_history = 0
        pool = Pool(processes=nparal)

        trial = 0
        while stabilization_history < stabilization_number:
            args = list(best_volume * np.ones(10))

            ret = pool.map(worker_star, zip(repeat(method), repeat(composition), repeat(periodic), args))

            ngood = 0
            for structure in ret:
                if structure is not None:
                    ngood += 1
                    if best_structure is not None:
                        if structure.volume < best_structure.volume:
                            best_structure = structure
                    else:
                        best_structure = structure

            # log.debug('Good structures: %d/10  Best volume: %7.3f' % (ngood, best_structure.volume))
            if best_structure is not None and best_volume > best_structure.volume:
                best_volume = best_structure.volume
                stabilization_history = 0
            else:
                stabilization_history += 1
            trial += 1

            # log.debug('Trial: %4d  Volume: %7.2f  Optimal Volume: %7.2f  Ratio: %5.2f' %
            #          (trial, best_volume, optimal_volume, best_volume/optimal_volume))

        pool.close()

        if best_structure is not None and periodic:
            # Analysis of the quality for the best structure
            rpos = best_structure.reduced
            for i, j in combinations(range(natom), 2):
                distance = best_structure.lattice.minimal_distance(rpos[i], rpos[j])
                covalent_distance = sum(covalent_radius([symbols[i], symbols[j]]))
                if distance < covalent_distance:
                    pcm_log.debug('Covalent distance: %7.4f  Minimal distance: %7.4f  Difference: %7.3e' %
                                  (covalent_distance, distance, covalent_distance - distance))

        best_structure.canonical_form()
        return best_structure
예제 #6
0
    def random_cell(composition,
                    method='stretching',
                    stabilization_number=20,
                    nparal=5,
                    periodic=True):
        """
        Generate a random cell
        There are two algorithms implemented:

        scaling: Generate a random cell and random distribution of atoms and
                scale the lattice to separate the atoms.

        stretching: Generating a random cell and random distribution of atoms
                    and stretching their bonds until the distance between any
                    two atoms is always greater than the sum of covalent radius.

        :param composition: (pychemia.Composition)
        :param method: (str)
        :param stabilization_number: (int)
        :param nparal: (int)
        :param periodic: (bool)
        :return:

        Examples:
        >>> import pychemia
        >>> import os
        >>> st = pychemia.Structure.random_cell('LiAlCl4', stabilization_number=3)
        >>> st.natom
        6
        >>> st.save_json('test.json')
        >>> st2 = pychemia.Structure.load_json('test.json')
        >>> st == st2
        True
        >>> os.remove('test.json')
        """
        comp = Composition(composition)
        pcm_log.debug('Generating a random structure with composition: ' +
                      str(comp.composition))
        natom = comp.natom
        symbols = comp.symbols

        best_volume = sys.float_info.max
        best_volume = float('inf')
        best_structure = None
        optimal_volume = comp.covalent_volume('cubes')
        stabilization_history = 0
        pool = Pool(processes=nparal)

        trial = 0
        while stabilization_history < stabilization_number:
            args = list(best_volume * np.ones(10))

            ret = pool.map(
                worker_star,
                zip(repeat(method), repeat(composition), repeat(periodic),
                    args))

            ngood = 0
            for structure in ret:
                if structure is not None:
                    ngood += 1
                    if best_structure is not None:
                        if structure.volume < best_structure.volume:
                            best_structure = structure
                    else:
                        best_structure = structure

            # log.debug('Good structures: %d/10  Best volume: %7.3f' % (ngood, best_structure.volume))
            if best_structure is not None and best_volume > best_structure.volume:
                best_volume = best_structure.volume
                stabilization_history = 0
            else:
                stabilization_history += 1
            trial += 1

            # log.debug('Trial: %4d  Volume: %7.2f  Optimal Volume: %7.2f  Ratio: %5.2f' %
            #          (trial, best_volume, optimal_volume, best_volume/optimal_volume))

        pool.close()

        if best_structure is not None and periodic:
            # Analysis of the quality for the best structure
            rpos = best_structure.reduced
            for i, j in combinations(range(natom), 2):
                distance = best_structure.lattice.minimal_distance(
                    rpos[i], rpos[j])
                covalent_distance = sum(
                    covalent_radius([symbols[i], symbols[j]]))
                if distance < covalent_distance:
                    pcm_log.debug(
                        'Covalent distance: %7.4f  Minimal distance: %7.4f  Difference: %7.3e'
                        % (covalent_distance, distance,
                           covalent_distance - distance))

        best_structure.canonical_form()
        return best_structure
예제 #7
0
def random_structure(method, composition, periodic=True, best_volume=1E10):
    comp = Composition(composition)
    natom = comp.natom
    symbols = comp.symbols
    np.random.seed(struct.unpack("<L", os.urandom(4))[0])

    if periodic:
        new_structure = None

        assert (method in ['scaling', 'stretching'])

        if method == 'scaling':
            lattice = Lattice.random_cell(comp)
            # Random reduced positions
            rpos = np.random.rand(natom, 3)
            mins = [min(rpos[:, i]) for i in range(3)]
            rpos -= mins

            new_lattice = lattice.scale(symbols, rpos, tolerance=1.0)
        else:
            lattice = Lattice.random_cell(comp)
            # Random reduced positions
            rpos = np.random.rand(natom, 3)
            mins = [min(rpos[:, i]) for i in range(3)]
            rpos -= mins

            new_lattice = lattice.stretch(symbols,
                                          rpos,
                                          tolerance=1.0,
                                          extra=0.1)

        if new_lattice.volume < best_volume:
            test = True
            for i in range(natom):
                for j in range(i + 1, natom):
                    distance = new_lattice.minimal_distance(rpos[i], rpos[j])
                    covalent_dim = sum(
                        covalent_radius([symbols[i], symbols[j]]))
                    if distance < covalent_dim:
                        test = False
            if test:
                new_structure = Structure(symbols=symbols,
                                          reduced=rpos,
                                          cell=new_lattice.cell,
                                          periodicity=True)
            else:
                new_structure = None
    else:
        pos = np.random.rand(natom, 3)

        mindis = cluster_minimal_distance(pos)
        if mindis == 0:
            raise ValueError("Distance too small")

        max_cov = np.max(covalent_radius(symbols))
        pos *= max_cov / mindis

        current_volume = (max(pos[:, 0]) - min(pos[:, 0])) * (max(
            pos[:, 1]) - min(pos[:, 1])) * (max(pos[:, 2]) - min(pos[:, 2]))

        if current_volume < best_volume:
            new_structure = Structure(symbols=symbols,
                                      positions=pos,
                                      periodicity=False)
        else:
            new_structure = None

    return new_structure
예제 #8
0
def random_structure(method, composition, periodic=True, max_volume=1E10):
    """
    Random Structure created  by random positioning of atoms followed by either scaling of the cell or
    adding a sheer stretching along the smaller distances. The purpose of the lattice change is to avoid any two
    atoms to be closer than the sum of their covalent radius.

    :param method: Can be 'stretching' or 'scaling'.
    :param composition: Can be a Composition object or formula.
    :param periodic: If True, the structure will be periodical in all directions, otherwise a finite system is created.
    :param max_volume: Threshold for creating the Structure, if the volume exceeds the target the method returns None
    :return: Structure if the volume is below than best_volume, None otherwise

    >>> st = random_structure(method='scaling', composition='H2O', periodic=False)
    >>> st.natom
    3
    >>> st = random_structure(method='stretching', composition='NaCl', periodic=True)
    >>> st.natom
    2
    """
    comp = Composition(composition)
    natom = comp.natom
    symbols = comp.symbols
    np.random.seed(struct.unpack("<L", os.urandom(4))[0])

    if periodic:
        new_structure = None

        assert (method in ['scaling', 'stretching'])

        while True:
            trial = 0

            if method == 'scaling':
                lattice = Lattice.random_cell(comp)
                # Random reduced positions
                rpos = np.random.rand(natom, 3)
                mins = [min(rpos[:, i]) for i in range(3)]
                rpos -= mins

                new_lattice = lattice
            else:
                lattice = Lattice.random_cell(comp)
                # Random reduced positions
                rpos = np.random.rand(natom, 3)
                mins = [min(rpos[:, i]) for i in range(3)]
                rpos -= mins

                new_lattice = lattice.stretch(symbols,
                                              rpos,
                                              tolerance=1.0,
                                              extra=0.1)

            if new_lattice.volume < max_volume:
                test = True
                for i in range(natom):
                    for j in range(i + 1, natom):
                        distance = new_lattice.minimal_distance(
                            rpos[i], rpos[j])
                        covalent_dim = sum(
                            covalent_radius([symbols[i], symbols[j]]))
                        if distance < covalent_dim:
                            test = False
                if test:
                    new_structure = Structure(symbols=symbols,
                                              reduced=rpos,
                                              cell=new_lattice.cell,
                                              periodicity=True)
                    minimal_distance = np.min(new_structure.distance_matrix() +
                                              10 * np.eye(new_structure.natom))
                    break
                else:
                    print(
                        "Trial failed, distance %f is less than covalent radious %f"
                        % (distance, covalent_dim))
                    trial += 1

            if trial > 100:
                print("Leaving after 100 attemps")
                break

        # else:
        #     print('Volume of Structure %f is larger than max_volume=%f' % (new_lattice.volume, max_volume))
        #     new_structure = None
    else:
        pos = np.random.rand(natom, 3)

        mindis = cluster_minimal_distance(pos)
        if mindis == 0:
            raise ValueError("Distance too small")

        max_cov = np.max(covalent_radius(symbols))
        pos *= max_cov / mindis

        current_volume = (max(pos[:, 0]) - min(pos[:, 0])) * (max(
            pos[:, 1]) - min(pos[:, 1])) * (max(pos[:, 2]) - min(pos[:, 2]))

        if current_volume < max_volume:
            new_structure = Structure(symbols=symbols,
                                      positions=pos,
                                      periodicity=False)
        else:
            print('Volume of Structure %f is larger than max_volume=%f' %
                  (current_volume, max_volume))
            new_structure = None

    return new_structure