Exemplo n.º 1
0
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        comp = self.composition.composition.copy()
        rnd = random.random()
        natom_limit = self.max_comp_mult * self.composition.natom / self.composition.gcd
        condition = {
            'structure.nspecies': self.composition.nspecies,
            'structure.natom': {
                '$lte': natom_limit
            }
        }

        if self.pcdb_source is None or self.pcdb_source.entries.find(
                condition).count() <= len(self.source_blacklist):
            rnd = 0
        origin = None

        if self.pcdb_source is None or rnd < random_probability or self.composition.nspecies > 1:
            pcm_log.debug('Random Structure')
            factor = np.random.randint(self.min_comp_mult,
                                       self.max_comp_mult + 1)
            for i in comp:
                comp[i] *= factor
            structure = Structure.random_cell(comp,
                                              method='stretching',
                                              stabilization_number=5,
                                              nparal=5,
                                              periodic=True)
        else:
            pcm_log.debug('From source')
            while True:

                entry = None
                condition['properties.spacegroup'] = random.randint(1, 230)
                print('Trying', condition['properties.spacegroup'])
                for ientry in self.pcdb_source.entries.find(condition):
                    if ientry['_id'] not in self.source_blacklist:
                        entry = ientry
                        break
                if entry is not None:
                    origin = entry['_id']
                    structure = self.pcdb_source.get_structure(entry['_id'])
                    factor = covalent_radius(
                        self.composition.species[0]) / covalent_radius(
                            structure.species[0])
                    print('From source: %s Spacegroup: %d Scaling: %7.3f' %
                          (structure.formula,
                           entry['properties']['spacegroup'], factor))
                    structure.set_cell(
                        np.dot(factor * np.eye(3), structure.cell))
                    structure.symbols = structure.natom * self.composition.species
                    self.source_blacklist.append(entry['_id'])
                    break

        return self.new_entry(structure), origin
Exemplo n.º 2
0
    def scale(self, symbols, rpos, tolerance=1.0):
        lattice = self.copy()
        factor = 1.0
        for i in range(len(rpos)):
            # This is to separate each atom from its own image
            covalent_dim = 2.0 * tolerance * covalent_radius(symbols[i])

            this_factor = covalent_dim / lattice.a
            if this_factor > factor:
                factor = this_factor
            this_factor = covalent_dim / lattice.b
            if this_factor > factor:
                factor = this_factor
            this_factor = covalent_dim / lattice.c
            if this_factor > factor:
                factor = this_factor

            for j in range(i + 1, len(rpos)):
                distance = lattice.minimal_distance(rpos[i], rpos[j])
                covalent_dim = tolerance * sum(covalent_radius([symbols[i], symbols[j]]))
                this_factor = covalent_dim / distance
                if this_factor > factor:
                    factor = this_factor
        a = lattice.a
        b = lattice.b
        c = lattice.c
        alpha = lattice.alpha
        beta = lattice.beta
        gamma = lattice.gamma
        return Lattice().from_parameters_to_cell(factor * a, factor * b, factor * c, alpha, beta, gamma)
Exemplo n.º 3
0
def get_surface_atoms_new(structure, use_covalent_radius=False):
    dln = scipy.spatial.Delaunay(structure.positions)

    if use_covalent_radius:
        simplices = []
        for j in dln.simplices:
            discard = False
            for ifacet in list(itertools.combinations(j, 3)):
                for ipair in itertools.combinations(ifacet, 2):
                    distance = np.linalg.norm(structure.positions[ipair[0]] - structure.positions[ipair[1]])
                    cov_distance = covalent_radius(structure.symbols[ipair[0]]) + covalent_radius(
                        structure.symbols[ipair[1]])
                    if distance > 3.0*cov_distance:
                        print('Distance: %f Cov-distance: %f' % (distance, cov_distance))
                        discard = True
                        break
            if not discard:
                print(j)
                simplices.append(j)
    else:
        simplices = dln.simplices

    c = np.array([[sorted(list(y)) for y in (itertools.combinations(x, 3))] for x in simplices])
    d = [list(x) for x in c.reshape((-1, 3))]

    ret = []
    dups = []
    for i in range(len(d) - 1):
        if d[i] in d[i+1:]:
            dups.append(d[i])
    for i in d:
        if i not in dups:
            ret.append(i)
    return np.unique(np.array(ret).flatten())
Exemplo n.º 4
0
def get_surface_atoms_new(structure, use_covalent_radius=False):
    dln = scipy.spatial.Delaunay(structure.positions)

    if use_covalent_radius:
        simplices = []
        for j in dln.simplices:
            discard = False
            for ifacet in list(itertools.combinations(j, 3)):
                for ipair in itertools.combinations(ifacet, 2):
                    distance = np.linalg.norm(structure.positions[ipair[0]] - structure.positions[ipair[1]])
                    cov_distance = covalent_radius(structure.symbols[ipair[0]]) + covalent_radius(
                        structure.symbols[ipair[1]])
                    if distance > 3.0*cov_distance:
                        print('Distance: %f Cov-distance: %f' % (distance, cov_distance))
                        discard = True
                        break
            if not discard:
                print(j)
                simplices.append(j)
    else:
        simplices=dln.simplices

    c = np.array([[sorted(list(y)) for y in (itertools.combinations(x, 3))] for x in simplices])
    d = [list(x) for x in c.reshape((-1, 3))]

    ret = []
    dups = []
    for i in range(len(d) - 1):
        if d[i] in d[i+1:]:
            dups.append(d[i])
    for i in d:
        if i not in dups:
            ret.append(i)
    return np.unique(np.array(ret).flatten())
Exemplo n.º 5
0
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        entry_id = None
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        factor = np.random.randint(self.min_comp_mult, self.max_comp_mult + 1)
        comp = self.composition.composition.copy()
        #print("Initial composition: %s" % comp)
        #print(Composition(comp))
        #print(Composition(comp).symbols)
        for i in comp:
            comp[i] *= factor
        new_comp = Composition(comp)

        while True:
            rnd = random.random()
            condition = {
                'structure.nspecies': new_comp.nspecies,
                'structure.natom': new_comp.natom
            }
            if self.pcdb_source is None:
                rnd = 0
            elif len(self.sources[factor]) == 0:
                rnd = 0
            if self.pcdb_source is None or rnd < random_probability:
                pcm_log.debug('Random Structure')
                structure = Structure.random_cell(new_comp,
                                                  method='stretching',
                                                  stabilization_number=5,
                                                  nparal=5,
                                                  periodic=True)
                break
            else:
                pcm_log.debug('From source')
                entry_id = self.sources[factor][np.random.randint(
                    0, len(self.sources[factor]))]
                structure = self.pcdb_source.get_structure(entry_id)
                print("chosen structure from database =", structure)
                sym = CrystalSymmetry(structure)

                scale_factor = float(
                    np.max(covalent_radius(new_comp.species)) /
                    np.max(covalent_radius(structure.species)))
                reduce_scale = scale_factor**(1. / 3)  # WIH
                msg = 'Mult: %d natom: %d From source: %s Spacegroup: %d Scaling: %7.3f'
                print(msg % (factor, structure.natom, structure.formula,
                             sym.number(), scale_factor))
                # structure.set_cell(np.dot(scale_factor * np.eye(3), structure.cell)) # WIH
                structure.set_cell(
                    np.dot(reduce_scale * np.eye(3), structure.cell))  # WIH
                print("symbols before change = ", structure.symbols)
                structure.symbols = new_comp.symbols
                print("symbols after change = ", structure.symbols)
                self.sources[factor].remove(entry_id)
                break

        return self.new_entry(structure), entry_id
Exemplo n.º 6
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
        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)
                minimal_distance = np.min(new_structure.distance_matrix() + 10 * np.eye(new_structure.natom))
                # print(minimal_distance)

            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
Exemplo n.º 7
0
    def scale(self, symbols, rpos, tolerance=1.0):
        lattice = self.copy()
        factor = 1.0
        for i in range(len(rpos)):
            # This is to separate each atom from its own image
            covalent_dim = 2.0 * tolerance * covalent_radius(symbols[i])

            this_factor = covalent_dim / lattice.a
            if this_factor > factor:
                factor = this_factor
            this_factor = covalent_dim / lattice.b
            if this_factor > factor:
                factor = this_factor
            this_factor = covalent_dim / lattice.c
            if this_factor > factor:
                factor = this_factor

            for j in range(i + 1, len(rpos)):
                distance = lattice.minimal_distance(rpos[i], rpos[j])
                covalent_dim = tolerance * sum(covalent_radius([symbols[i], symbols[j]]))
                this_factor = covalent_dim / distance
                if this_factor > factor:
                    factor = this_factor
        a = lattice.a
        b = lattice.b
        c = lattice.c
        alpha = lattice.alpha
        beta = lattice.beta
        gamma = lattice.gamma
        return Lattice().from_parameters_to_cell(factor * a, factor * b, factor * c, alpha, beta, gamma)
Exemplo n.º 8
0
    def hardness_XX(self, initial_cutoff_radius=0.8, use_laplacian=True):

        bonds, coordination, cutoff_radius = self.bonds_coordination(
            initial_cutoff_radius=initial_cutoff_radius,
            use_laplacian=use_laplacian)

        sigma = 3.0
        c_hard = 1300.0
        xprod = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        atomicnumbers = atomic_number(self.structure.species)

        pcm_log.debug('Atomic numbers in the structure : %s' %
                      str(atomicnumbers))

        for i in atomicnumbers:
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)

        if f_d == 0:
            pcm_log.debug('Returning zero as hardness. f_d= %10.3f' % f_d)
            return 0.0
        f = 1.0 - (self.structure.nspecies *
                   f_n**(1.0 / self.structure.nspecies) / f_d)**2

        diff_bonds = [x for x in bonds if len(bonds[x]) > 0]

        for pair in diff_bonds:
            i1 = pair[0]
            i2 = pair[1]

            ei = valence(self.structure.symbols[i1]) / covalent_radius(
                self.structure.symbols[i1])
            ej = valence(self.structure.symbols[i2]) / covalent_radius(
                self.structure.symbols[i2])

            for dij in bonds[pair]:
                sij = math.sqrt(
                    ei * ej) / (coordination[i1] * coordination[i2]) / dij
                xprod *= sij

            num_i_j_bonds = len(bonds[pair])
            pcm_log.debug('Number of bonds for pair %s = %d' %
                          (str(pair), num_i_j_bonds))
            tot += num_i_j_bonds

        vol = self.structure.volume

        pcm_log.debug("Structure volume: %7.3f" % vol)
        pcm_log.debug("Total number of bonds: %d" % tot)
        pcm_log.debug("Bonds: %s" % str(bonds))

        hardness_value = (c_hard / vol) * tot * (xprod**(1. / tot)) * math.exp(
            -sigma * f)

        return round(hardness_value, 3), cutoff_radius, coordination
Exemplo n.º 9
0
    def hardness_XX(self, initial_cutoff_radius=0.8, use_laplacian=True):
        """
        Implementation of Hardness algorithm:
        
        First-principles structural design of superhard materials
        J. Chem. Phys. 138, 114101 (2013); https://doi.org/10.1063/1.4794424
        Xinxin Zhang, et al.
        """

        bonds, coordination, cutoff_radius = self.bonds_coordination(initial_cutoff_radius=initial_cutoff_radius,
                                                                     use_laplacian=use_laplacian)

        sigma = 3.0
        c_hard = 1300.0
        xprod = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        atomicnumbers = atomic_number(self.structure.species)

        pcm_log.debug('Atomic numbers in the structure : %s' % str(atomicnumbers))

        for i in atomicnumbers:
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)

        if f_d == 0:
            pcm_log.debug('Returning zero as hardness. f_d= %10.3f' % f_d)
            return 0.0
        f = 1.0 - (self.structure.nspecies * f_n ** (1.0 / self.structure.nspecies) / f_d) ** 2

        diff_bonds = [x for x in bonds if len(bonds[x]) > 0]

        for pair in diff_bonds:
            i1 = pair[0]
            i2 = pair[1]

            ei = valence(self.structure.symbols[i1]) / covalent_radius(self.structure.symbols[i1])
            ej = valence(self.structure.symbols[i2]) / covalent_radius(self.structure.symbols[i2])

            for dij in bonds[pair]:
                sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / dij
                xprod *= sij

            num_i_j_bonds = len(bonds[pair])
            pcm_log.debug('Number of bonds for pair %s = %d' % (str(pair), num_i_j_bonds))
            tot += num_i_j_bonds

        vol = self.structure.volume

        pcm_log.debug("Structure volume: %7.3f" % vol)
        pcm_log.debug("Total number of bonds: %d" % tot)
        pcm_log.debug("Bonds: %s" % str(bonds))

        hardness_value = (c_hard / vol) * tot * (xprod ** (1. / tot)) * math.exp(-sigma * f)

        return round(hardness_value, 3), cutoff_radius, coordination
Exemplo n.º 10
0
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        entry_id = None
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        factor = np.random.randint(self.min_comp_mult, self.max_comp_mult + 1)
        comp = self.composition.composition.copy()
        # print("Initial composition: %s" % comp)
        # print(Composition(comp))
        # print(Composition(comp).symbols)
        for i in comp:
            comp[i] *= factor
        new_comp = Composition(comp)

        while True:
            rnd = random.random()
            condition = {'structure.nspecies': new_comp.nspecies,
                         'structure.natom': new_comp.natom}
            if self.pcdb_source is None:
                rnd = 0
            elif len(self.sources[factor]) == 0:
                rnd = 0
            if self.pcdb_source is None or rnd < random_probability:
                pcm_log.debug('Random Structure')
                structure = Structure.random_cell(new_comp, method='stretching', stabilization_number=5, nparal=5,
                                                  periodic=True)
                break
            else:
                pcm_log.debug('From source')
                entry_id = self.sources[factor][np.random.randint(0, len(self.sources[factor]))]
                structure = self.pcdb_source.get_structure(entry_id)
                print("chosen structure from database =", structure)
                sym = CrystalSymmetry(structure)

                scale_factor = float(np.max(covalent_radius(new_comp.species)) /
                                     np.max(covalent_radius(structure.species)))
                reduce_scale = scale_factor ** (1. / 3)    # WIH
                msg = 'Mult: %d natom: %d From source: %s Spacegroup: %d Scaling: %7.3f'
                print(msg % (factor, structure.natom, structure.formula, sym.number(), scale_factor))
                # structure.set_cell(np.dot(scale_factor * np.eye(3), structure.cell)) # WIH
                structure.set_cell(np.dot(reduce_scale * np.eye(3), structure.cell))  # WIH
                print("symbols before change = ", structure.symbols)
                structure.symbols = new_comp.symbols
                print("symbols after change = ", structure.symbols)
                self.sources[factor].remove(entry_id)
                break

        return self.new_entry(structure), entry_id
Exemplo n.º 11
0
    def hardness_XX(self, initial_cutoff_radius=0.8, use_laplacian=True):

        bonds, coordination, cutoff_radius = self.bonds_coordination(initial_cutoff_radius=initial_cutoff_radius,
                                                                     use_laplacian=use_laplacian, verbose=True)

        sigma = 3.0
        c_hard = 1300.0
        xprod = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        atomicnumbers = atomic_number(self.structure.species)

        pcm_log.debug('Atomic numbers in the structure : %s' % str(atomicnumbers))

        for i in atomicnumbers:
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)

        if f_d == 0:
            pcm_log.debug('Returning zero as hardness. f_d= %10.3f' % f_d)
            return 0.0
        f = 1.0 - (self.structure.nspecies * f_n ** (1.0 / self.structure.nspecies) / f_d) ** 2

        diff_bonds = [x for x in bonds if len(bonds[x]) > 0]

        for pair in diff_bonds:
            i1 = pair[0]
            i2 = pair[1]

            ei = valence(self.structure.symbols[i1]) / covalent_radius(self.structure.symbols[i1])
            ej = valence(self.structure.symbols[i2]) / covalent_radius(self.structure.symbols[i2])

            for dij in bonds[pair]:
                sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / dij
                xprod *= sij

            num_i_j_bonds = len(bonds[pair])
            pcm_log.debug('Number of bonds for pair %s = %d' % (str(pair), num_i_j_bonds))
            tot += num_i_j_bonds

        vol = self.structure.volume

        pcm_log.debug("Structure volume: %7.3f" % vol)
        pcm_log.debug("Total number of bonds: %d" % tot)
        pcm_log.debug("Bonds: %s" % str(bonds))

        hardness_value = (c_hard / vol) * tot * (xprod ** (1. / tot)) * math.exp(-sigma * f)

        return round(hardness_value, 3), cutoff_radius, coordination
Exemplo n.º 12
0
    def add_random(self, random_probability=0.3):
        """
        Add one random structure to the population
        """
        structure = Structure()
        if self.composition is None:
            raise ValueError('No composition associated to this population')
        comp = self.composition.composition.copy()
        rnd = random.random()
        natom_limit = self.max_comp_mult * self.composition.natom / self.composition.gcd
        condition = {'structure.nspecies': self.composition.nspecies,
                     'structure.natom': {'$lte': natom_limit}}

        if self.pcdb_source is None or self.pcdb_source.entries.find(condition).count() <= len(self.source_blacklist):
            rnd = 0
        origin = None

        if self.pcdb_source is None or rnd < random_probability or self.composition.nspecies > 1:
            pcm_log.debug('Random Structure')
            factor = np.random.randint(self.min_comp_mult, self.max_comp_mult + 1)
            for i in comp:
                comp[i] *= factor
            structure = Structure.random_cell(comp, method='stretching', stabilization_number=5, nparal=5,
                                              periodic=True)
        else:
            pcm_log.debug('From source')
            while True:

                entry = None
                condition['properties.spacegroup'] = random.randint(1, 230)
                print('Trying', condition['properties.spacegroup'])
                for ientry in self.pcdb_source.entries.find(condition):
                    if ientry['_id'] not in self.source_blacklist:
                        entry = ientry
                        break
                if entry is not None:
                    origin = entry['_id']
                    structure = self.pcdb_source.get_structure(entry['_id'])
                    factor = covalent_radius(self.composition.species[0]) / covalent_radius(structure.species[0])
                    print('From source: %s Spacegroup: %d Scaling: %7.3f' % (structure.formula,
                                                                             entry['properties']['spacegroup'],
                                                                             factor))
                    structure.set_cell(np.dot(factor * np.eye(3), structure.cell))
                    structure.symbols = structure.natom * self.composition.species
                    self.source_blacklist.append(entry['_id'])
                    break

        return self.new_entry(structure), origin
Exemplo n.º 13
0
    def covalent_volume(self, packing='cubes'):
        """
        Returns the volume occupied by a given formula
        assuming a 'cubes' packing or 'spheres' packing

        :param packing: (str) The kind of packing could be 'cubes' or 'spheres'

        :rtype : (float)

        >>> import pychemia
        >>> comp=pychemia.Composition('C5H10')
        >>> comp.covalent_volume()
        19.942320000000002
        >>> comp.covalent_volume(packing='spheres')
        10.441774334589468

        """
        if packing == 'cubes':
            factor = 8
        elif packing == 'spheres':
            factor = 4 * pi / 3.0
        else:
            raise ValueError('Non-valid packing value ', packing)

        # find volume of unit cell by adding cubes
        volume = 0.0
        for specie in self:
            number_atoms_specie = self.composition[specie]
            # Pack each atom in a cube (2*r)^3
            volume += factor * number_atoms_specie * covalent_radius(specie)**3
        return volume
Exemplo n.º 14
0
    def covalent_volume(self, packing='cubes'):
        """
        Returns the volume occupied by a given formula
        assuming a 'cubes' packing or 'spheres' packing

        :param packing: (str) The kind of packing could be 'cubes' or 'spheres'

        :rtype : (float)

        >>> import pychemia
        >>> comp=pychemia.Composition('C5H10')
        >>> comp.covalent_volume()
        19.942320000000002
        >>> comp.covalent_volume(packing='spheres')
        10.441774334589468

        """
        if packing == 'cubes':
            factor = 8
        elif packing == 'spheres':
            factor = 4 * pi / 3.0
        else:
            raise ValueError('Non-valid packing value ', packing)

        # find volume of unit cell by adding cubes
        volume = 0.0
        for specie in self:
            number_atoms_specie = self.composition[specie]
            # Pack each atom in a cube (2*r)^3
            volume += factor * number_atoms_specie * covalent_radius(specie) ** 3
        return volume
Exemplo n.º 15
0
    def get_bonds_coordination(self, tolerance=1, ensure_conectivity=False):

        bonds_dict, all_distances = self.get_all_distances()
        bonds = []
        tolerances=[]
        for i in range(self.natom):
            tole = tolerance
            while True:
                tmp_bonds = []
                min_proportion = sys.float_info.max
                for j in bonds_dict[str(i)]:
                    atom1 = self.symbols[all_distances[j]['pair'][0]]
                    atom2 = self.symbols[all_distances[j]['pair'][1]]
                    sum_covalent_radius = sum(covalent_radius([atom1, atom2]))
                    distance = all_distances[j]['distance']
                    if distance == 0.0:
                        continue
                    proportion = distance/sum_covalent_radius
                    min_proportion = min(min_proportion, proportion)
                    if proportion <= tole:
                        #print all_distances[j]
                        tmp_bonds.append(j)
                if len(tmp_bonds) == 0 and ensure_conectivity:
                    #print 'Changing tolerance'
                    tole = min_proportion
                else:
                    bonds.append(tmp_bonds)
                    tolerances.append(min_proportion)
                    break

        coordination = [len(x) for x in bonds]
        return bonds, coordination, all_distances, tolerances
Exemplo n.º 16
0
def compute_bonds(typat, xcart, znucl):
    """
    Compute the bond lengths of all the atoms
    inside the unitary box (NEEDS EXTENSION TO
    OUTSIDE THE BOX)

    :param typat: (int, list) Type of atoms
    :param xcart: (numpy.ndarray) Cartesian positions
    :param znucl: (int, list) Atomic number for atoms in typat
    :return:
    """

    npxcart = np.array(xcart).reshape((-1, 3))
    if isinstance(typat, int):
        lsttypat = [typat]
    else:
        lsttypat = typat
    if isinstance(znucl, (int, float)):
        lstznucl = [znucl]
    else:
        lstznucl = znucl
    covrad = [covalent_radius(lstznucl[iatom - 1]) for iatom in lsttypat]

    bonds = []
    for iatom in range(len(npxcart)):
        for jatom in range(iatom + 1, len(npxcart)):
            # Compute bond length between atoms i and j
            bl = math.sqrt(sum((npxcart[jatom] - npxcart[iatom])**2))
            if 1.35 * (covrad[iatom] + covrad[jatom]) > bl:
                bonds.append(
                    [iatom, jatom, bl, (npxcart[jatom] - npxcart[iatom]) / bl])

    return bonds
Exemplo n.º 17
0
    def create_pov(self):

        ret = """
#version 3.7;
#include "colors.inc"    // The include files contain
#include "stones.inc"    // pre-defined scene elements
#include "glass.inc"
background{rgb 0}

"""
        if self.structure.is_crystal:
            self.distance = max(self.structure.lattice.lengths)
        else:
            self.distance = 10

        ret += "#declare r=%7.3f;\n #declare s=%7.3f;" % (self.distance, self.distance)

        ret += "camera {\n"
        ret += "\tlocation <%7.3f, %7.3f, %7.3f>\n" % (1.3 * self.distance, 1.3 * self.distance, -1.3 * self.distance)
        ret += "\tlook_at  <%7.3f, %7.3f, %7.3f>\n" % tuple(0.5 * sum(self.structure.cell[:]))
        ret += "}\n\n"

        if self.structure.nsites > 0:
            d = self.distance
            ret += "light_source { <%7.3f, %7.3f, %7.3f> color White}\n" % (2 * d, 2 * d, 2 * d)

        for imagx in np.arange(-1, 2):
            for imagy in np.arange(-1, 2):
                for imagz in np.arange(-1, 2):

                    for site in self.structure:
                        for symbol in site.symbols:
                            cell = self.structure.cell
                            x = site.position[0] - imagx * cell[0, 0] - imagy * cell[1, 0] - imagz * cell[2, 0]
                            y = site.position[1] - imagx * cell[0, 1] - imagy * cell[1, 1] - imagz * cell[2, 1]
                            z = site.position[2] - imagx * cell[0, 2] - imagy * cell[1, 2] - imagz * cell[2, 2]
                            if (x - self.distance) ** 2 + (y - self.distance) ** 2 + (z + self.distance) ** 2 < 2:
                                continue
                            cr = 0.5 * covalent_radius(symbol)
                            rgb = cpk_colors[atomic_number(symbol)]
                            color = 'rgb < %7.3f, %7.3f, %7.3f>' % (rgb[0], rgb[1], rgb[2])
                            ret += "sphere {\n"
                            ret += "\t<%7.3f, %7.3f, %7.3f>, %7.3f\n\ttexture {\n" % (x, y, z, cr)
                            ret += "\t\tpigment { color %s filter 0.4 transmit %7.3f}\n" % \
                                   (color, 1 - 0.9 * np.exp(-0.1 * (abs(imagx) + abs(imagy) + abs(imagz))))
                            ret += "\t\tnormal { bumps 0.8 scale 0.1 }\n\t\tfinish { phong %7.3f }\n\t}\n}\n\n" % \
                                   np.exp(-0.1 * (abs(imagx) + abs(imagy) + abs(imagz)))

                            if self.structure.nsites <= 0:
                                ret += "light_source { <%7.3f, %7.3f, %7.3f> color White}\n" % (x, y, z)

        ret += """union{
#include "cell.pov"
    scale 1
    rotate <0, 0, 0>
    pigment{rgb <0.3,0.3,0.9>} finish{phong 0.9 ambient 0.42 reflection 0.1}
}
"""
        return ret
Exemplo n.º 18
0
    def plot(self, figname=None, size=(300, 325), view=(30, 30), color=(1.0, 1.0, 1.0)):

        fig = mlab.figure(size=size)
        figure = mlab.gcf()
        fig.scene.disable_render = True
        figure.scene.background = (0.0, 0.0, 0.0)
        mlab.view(0, 90, distance=0.2)
        assert (self.structure.natom > 0)

        x = self.structure.positions[:, 0]
        y = self.structure.positions[:, 1]
        z = self.structure.positions[:, 2]
        cr = covalent_radius(self.structure.symbols)
        s = np.apply_along_axis(np.linalg.norm, 1, self.structure.positions)

        mlab.points3d(x, y, z, s, scale_factor=1.0, resolution=8, opacity=1.0,
                      color=color,
                      scale_mode='none')

        if self.structure.is_crystal:
            frame, line1, line2, line3 = self.structure.get_cell().get_path()

            mlab.plot3d(frame[:, 0], frame[:, 1], frame[:, 2], tube_radius=.02, color=(1, 1, 1))
            mlab.plot3d(line1[:, 0], line1[:, 1], line1[:, 2], tube_radius=.02, color=(1, 1, 1))
            mlab.plot3d(line2[:, 0], line2[:, 1], line2[:, 2], tube_radius=.02, color=(1, 1, 1))
            mlab.plot3d(line3[:, 0], line3[:, 1], line3[:, 2], tube_radius=.02, color=(1, 1, 1))
        else:
            for i in range(self.structure.natom - 1):
                for j in range(i + 1, self.structure.natom):
                    vector = self.structure.positions[i] - self.structure.positions[j]
                    mvector = np.linalg.norm(vector)
                    uvector = 1.0 / mvector * vector
                    if 2 * mvector < covalent_radius(self.structure.symbols[i]) + \
                            covalent_radius(self.structure.symbols[j]):
                        pair = np.concatenate(
                            (self.structure.positions[i] - 0.1 * uvector,
                             self.structure.positions[j] + 0.1 * uvector)).reshape((-1, 3))
                        mlab.plot3d(pair[:, 0], pair[:, 1], pair[:, 2], tube_radius=0.15, opacity=1.0, color=(1, 1, 1))

        mlab.view(distance=12.0)
        fig.scene.disable_render = False
        if figname is not None:
            mlab.savefig(figname)
        return figure
Exemplo n.º 19
0
    def move(self, entry_id, entry_jd, factor=0.2, in_place=False):

        st_orig = self.get_structure(entry_id)
        st_dest = self.get_structure(entry_jd)

        cm = pychemia.analysis.ClusterMatch(st_orig, st_dest)
        cm.match()

        # pos_orig = np.array(entry_orig['structure']['positions']).reshape((-1, 3))
        # pos_dest = np.array(entry_dest['structure']['positions']).reshape((-1, 3))
        pos_orig = cm.structure1.positions
        pos_dest = cm.structure2.positions

        # Move to a position with negative energy
        reduc = 1
        new_positions = np.array(pos_orig)
        while True:
            new_positions = rotation_move(pos_orig, pos_dest, fraction=reduc * factor)
            new_structure = pychemia.Structure(positions=new_positions,
                                               symbols=st_orig.symbols,
                                               periodicity=False)
            lj = pychemia.code.LennardJones(new_structure)
            if lj.get_energy() < 0.0:
                print('Effective factor reduced to %7.3f, original factor %7.3f' % (reduc * factor, factor))
                break
            reduc -= 0.05
            if reduc <= 0.0:
                # print 'No movement effective'
                break

        # Avoid condition with atoms too close
        distance_matrix = scipy.spatial.distance_matrix(new_positions, new_positions)
        tmp = np.max(distance_matrix.flatten())
        # print 'Scaling by', tmp
        minimal_distance = np.min((distance_matrix + tmp * np.eye(len(new_positions))).flatten())

        if minimal_distance < 1E-8:
            print("Null distance between different atoms, no moving")
            new_positions = pos_orig

        if tmp > 5:
            # print 'Big scaling, better not to move'
            new_positions = pos_orig
        else:
            max_cov = np.max(covalent_radius(st_orig.symbols))
            new_positions *= max_cov / minimal_distance

        new_structure = pychemia.Structure(positions=new_positions, symbols=st_orig.symbols, periodicity=False)
        # print 'Density of cluster', new_structure.density

        if in_place:
            return self.pcdb.update(entry_id, structure=new_structure, properties={})
        else:
            return self.new_entry(new_structure, active=False)
Exemplo n.º 20
0
    def view_projections(self):
        """
        Show the 3 projections of the molecule in a single
        figure
        """
        import matplotlib.patches as mpatches
        from matplotlib.collections import PatchCollection
        from matplotlib.pylab import subplots

        fig, ax = subplots(nrows=1, ncols=3)
        fig.set_size_inches(15, 4)
        color = ['r', 'g', 'b']
        j = 0

        structure = self.get_structure()

        for i in structure.cell:
            ax[0].plot([0, i[0]], [0, i[1]], color[j] + '-', lw=3)
            ax[1].plot([0, i[1]], [0, i[2]], color[j] + '-', lw=3)
            ax[2].plot([0, i[2]], [0, i[0]], color[j] + '-', lw=3)
            j += 1

        proj = [[0, 1], [1, 2], [2, 0]]
        labels = [['x', 'y'], ['y', 'z'], ['z', 'x']]

        for j in range(3):

            patches = []
            for i in range(structure.natom):
                radius = 0.5 * covalent_radius(
                    atomic_number(structure.symbols[i]))
                pos = structure.positions[i]
                art = mpatches.Circle((pos[proj[j][0]], pos[proj[j][1]]),
                                      radius,
                                      fc='g',
                                      ec='g')
                patches.append(art)

            collection = PatchCollection(patches, color='k', alpha=0.5)

            col = ax[j].add_collection(collection)
            ax[j].set_xlim(
                min(structure.positions[:, proj[j][0]]) - 1,
                max(structure.positions[:, proj[j][0]]) + 1)
            ax[j].set_ylim(
                min(structure.positions[:, proj[j][1]]) - 1,
                max(structure.positions[:, proj[j][1]]) + 1)
            ax[j].set_aspect('equal', adjustable='datalim')
            ax[j].set_xlabel(labels[j][0])
            ax[j].set_ylabel(labels[j][1])

        return fig, ax
Exemplo n.º 21
0
    def bonds_coordination(self,
                           initial_cutoff_radius=0.8,
                           use_laplacian=True,
                           jump=0.01,
                           tol=1E-15):

        cutoff_radius = initial_cutoff_radius
        ad = self.all_distances()
        bonds = {}
        while True:
            laplacian = np.zeros((self.structure.natom, self.structure.natom),
                                 dtype=np.int8)

            for pair in ad:
                atom1 = self.structure.symbols[pair[0]]
                atom2 = self.structure.symbols[pair[1]]
                sum_covalent_radius = sum(covalent_radius([atom1, atom2]))
                condition = np.bitwise_and(
                    ad[pair]['distance'] < cutoff_radius * sum_covalent_radius,
                    ad[pair]['distance'] > 0)
                bonds[pair] = ad[pair]['distance'][condition]
                if len(bonds[pair]) > 0:
                    laplacian[pair[0], pair[1]] = -1
                    laplacian[pair[1], pair[0]] = -1
            for i in range(self.structure.natom):
                laplacian[i, i] = 0
                laplacian[i, i] = -sum(laplacian[i])

            if use_laplacian:
                if np.max(np.abs(laplacian)) == 0:
                    cutoff_radius += jump

                ev = numpy.linalg.eigvalsh(laplacian)

                if sum(ev < tol) > 1:
                    cutoff_radius += jump
                else:
                    break
            else:
                break
        coordination = np.zeros(self.structure.natom, dtype=int)
        for pair in bonds:
            coordination[pair[0]] += len(bonds[pair])
            coordination[pair[1]] += len(bonds[pair])

        return bonds, coordination, round(cutoff_radius, 3)
Exemplo n.º 22
0
def compute_bonds(typat, xcart, znucl):
    """
    Compute the bond lengths of all the atoms
    inside the unitary box (NEEDS EXTENSION TO
    OUTSIDE THE BOX)
    """

    covrad = [covalent_radius(znucl[iatom - 1]) for iatom in typat]

    bonds = []
    for iatom in range(len(xcart)):
        for jatom in range(iatom + 1, len(xcart)):
            # Compute bond length between atoms i and j
            bl = math.sqrt(sum((xcart[jatom] - xcart[iatom]) ** 2))
            if 1.35 * (covrad[iatom] + covrad[jatom]) > bl:
                bonds.append([iatom, jatom, bl, (xcart[jatom] - xcart[iatom]) / bl])

    return bonds
Exemplo n.º 23
0
    def view_projections(self):
        """
        Show the 3 projections of the molecule in a single
        figure
        """
        import matplotlib.patches as mpatches
        from matplotlib.collections import PatchCollection
        from matplotlib.pylab import subplots

        fig, ax = subplots(nrows=1, ncols=3)
        fig.set_size_inches(15, 4)
        color = ['r', 'g', 'b']
        j = 0

        structure = self.get_structure()

        for i in structure.cell:
            ax[0].plot([0, i[0]], [0, i[1]], color[j] + '-', lw=3)
            ax[1].plot([0, i[1]], [0, i[2]], color[j] + '-', lw=3)
            ax[2].plot([0, i[2]], [0, i[0]], color[j] + '-', lw=3)
            j += 1

        proj = [[0, 1], [1, 2], [2, 0]]
        labels = [['x', 'y'], ['y', 'z'], ['z', 'x']]

        for j in range(3):

            patches = []
            for i in range(structure.natom):
                radius = 0.5 * covalent_radius(atomic_number(structure.symbols[i]))
                pos = structure.positions[i]
                art = mpatches.Circle((pos[proj[j][0]], pos[proj[j][1]]), radius, fc='g', ec='g')
                patches.append(art)

            collection = PatchCollection(patches, color='k', alpha=0.5)

            col = ax[j].add_collection(collection)
            ax[j].set_xlim(min(structure.positions[:, proj[j][0]]) - 1, max(structure.positions[:, proj[j][0]]) + 1)
            ax[j].set_ylim(min(structure.positions[:, proj[j][1]]) - 1, max(structure.positions[:, proj[j][1]]) + 1)
            ax[j].set_aspect('equal', adjustable='datalim')
            ax[j].set_xlabel(labels[j][0])
            ax[j].set_ylabel(labels[j][1])

        return fig, ax
Exemplo n.º 24
0
    def stretch(self, symbols, rpos, tolerance=1.0, extra=0.1):
        # Dummy array that always will be overwritten
        eigv = np.array([1, 0, 0])
        lattice = self.copy()
        assert len(rpos) == len(symbols)
        natom = len(rpos)
        for i, j in combinations(range(natom), 2):
            ret = lattice.distance2(rpos[i], rpos[j])
            mindist = sys.float_info.max
            for k in ret:
                if 0 < ret[k]['distance'] < mindist:
                    mindist = ret[k]['distance']
                    eigv = ret[k]['image']

            covalent_distance = sum(covalent_radius([symbols[i], symbols[j]]))
            if mindist < tolerance * covalent_distance:
                factor = (tolerance + extra) * covalent_distance / mindist
                v1, v2, v3 = vector_set_perpendicular(eigv)
                matrix_a = matrix_from_eig(v1, v2, v3, factor, 1, 1)
                lattice = Lattice(np.dot(matrix_a, lattice.cell))
        return lattice
Exemplo n.º 25
0
    def stretch(self, symbols, rpos, tolerance=1.0, extra=0.1):
        # Dummy array that always will be overwritten
        eigv = np.array([1, 0, 0])
        lattice = self.copy()
        assert len(rpos) == len(symbols)
        natom = len(rpos)
        for i, j in combinations(range(natom), 2):
            ret = lattice.distance2(rpos[i], rpos[j])
            mindist = sys.float_info.max
            for k in ret:
                if 0 < ret[k]['distance'] < mindist:
                    mindist = ret[k]['distance']
                    eigv = ret[k]['image']

            covalent_distance = sum(covalent_radius([symbols[i], symbols[j]]))
            if mindist < tolerance * covalent_distance:
                factor = (tolerance + extra) * covalent_distance / mindist
                v1, v2, v3 = vector_set_perpendicular(eigv)
                matrix_a = matrix_from_eig(v1, v2, v3, factor, 1, 1)
                lattice = Lattice(np.dot(matrix_a, lattice.cell))
        return lattice
Exemplo n.º 26
0
    def plot(self):
        from mayavi import mlab
        assert(self.natom > 0)

        x = self.positions[:, 0]
        y = self.positions[:, 1]
        z = self.positions[:, 2]
        cr = covalent_radius(self.symbols)

        mlab.points3d(x, y, z, cr, scale_factor=1)

        if self.is_crystal:
            frame, line1, line2, line3 = self.get_cell().get_path()

            mlab.plot3d(frame[:, 0], frame[:, 1], frame[:, 2], tube_radius=.05, color=(1, 1, 1))
            mlab.plot3d(line1[:, 0], line1[:, 1], line1[:, 2], tube_radius=.05, color=(1, 1, 1))
            mlab.plot3d(line2[:, 0], line2[:, 1], line2[:, 2], tube_radius=.05, color=(1, 1, 1))
            mlab.plot3d(line3[:, 0], line3[:, 1], line3[:, 2], tube_radius=.05, color=(1, 1, 1))

        mlab.view()
        return mlab.gcf()
Exemplo n.º 27
0
    def bonds_coordination(self, initial_cutoff_radius=0.8, use_laplacian=True, jump=0.01, tol=1E-15):

        cutoff_radius = initial_cutoff_radius
        ad = self.all_distances()
        bonds = {}
        while True:
            laplacian = np.zeros((self.structure.natom, self.structure.natom), dtype=np.int8)

            for pair in ad:
                atom1 = self.structure.symbols[pair[0]]
                atom2 = self.structure.symbols[pair[1]]
                sum_covalent_radius = sum(covalent_radius([atom1, atom2]))
                condition = np.bitwise_and(ad[pair]['distance'] < cutoff_radius * sum_covalent_radius,
                                           ad[pair]['distance'] > 0)
                bonds[pair] = ad[pair]['distance'][condition]
                if len(bonds[pair]) > 0:
                    laplacian[pair[0], pair[1]] = -1
                    laplacian[pair[1], pair[0]] = -1
            for i in range(self.structure.natom):
                laplacian[i, i] = 0
                laplacian[i, i] = -sum(laplacian[i])

            if use_laplacian:
                if np.max(np.abs(laplacian)) == 0:
                    cutoff_radius += jump

                ev = numpy.linalg.eigvalsh(laplacian)

                if sum(ev < tol) > 1:
                    cutoff_radius += jump
                else:
                    break
            else:
                break
        coordination = np.zeros(self.structure.natom, dtype=int)
        for pair in bonds:
            coordination[pair[0]] += len(bonds[pair])
            coordination[pair[1]] += len(bonds[pair])

        return bonds, coordination, round(cutoff_radius, 3)
Exemplo n.º 28
0
def compute_bonds(typat, xcart, znucl):
    """
    Compute the bond lengths of all the atoms
    inside the unitary box (NEEDS EXTENSION TO
    OUTSIDE THE BOX)

    :param typat: (int, list) Type of atoms
    :param xcart: (numpy.ndarray) Cartesian positions
    :param znucl: (int, list) Atomic number for atoms in typat
    :return:
    """
    if isinstance(typat, int):
        lsttypat = [typat]
    else:
        lsttypat = typat
    if isinstance(znucl, (int, float)):
        lstznucl = [znucl]
    else:
        lstznucl = znucl

    covrad = [
        angstrom_bohr * covalent_radius(lstznucl[i - 1]) for i in lsttypat
    ]
    bonds = []
    for t in range(len(xcart)):
        bonds1 = []
        for i in range(len(xcart[t])):
            for j in range(i + 1, len(xcart[t])):
                # print xcart[t][j]
                # print xcart[t][i]
                # Compute bond length between atoms i and j
                bl = math.sqrt(sum((xcart[t][j] - xcart[t][i])**2))
                # print bl
                # print i,j
                # print covrad[i],covrad[j]
                if 1.35 * (covrad[i] + covrad[j]) > bl:
                    bonds1.append([i, j, bl, (xcart[t][j] - xcart[t][i]) / bl])
        bonds.append(bonds1)
    return bonds
Exemplo n.º 29
0
def compute_bonds(typat, xcart, znucl):
    """
    Compute the bond lengths of all the atoms
    inside the unitary box (NEEDS EXTENSION TO
    OUTSIDE THE BOX)

    :param typat: (int, list) Type of atoms
    :param xcart: (numpy.ndarray) Cartesian positions
    :param znucl: (int, list) Atomic number for atoms in typat
    :return:
    """
    print(typat)
    print(xcart)
    print(znucl)

    npxcart = np.array(xcart).reshape((-1, 3))
    if isinstance(typat, int):
        lsttypat = [typat]
    else:
        lsttypat = typat
    if isinstance(znucl, (int, float)):
        lstznucl = [znucl]
    else:
        lstznucl = znucl
    covrad = [covalent_radius(lstznucl[iatom - 1]) for iatom in lsttypat]

    bonds = []
    for iatom in range(len(npxcart)):
        for jatom in range(iatom + 1, len(npxcart)):
            # Compute bond length between atoms i and j
            bl = math.sqrt(sum((npxcart[jatom] - npxcart[iatom]) ** 2))
            if 1.35 * (covrad[iatom] + covrad[jatom]) > bl:
                bonds.append([iatom, jatom, bl, (npxcart[jatom] - npxcart[iatom]) / bl])
            else:
                print("small distance: %s" % bl)

    return bonds
Exemplo n.º 30
0
def compute_bonds(typat, xcart, znucl):
    """
    Compute the bond lengths of all the atoms
    inside the unitary box (NEEDS EXTENSION TO
    OUTSIDE THE BOX)

    :param typat: (int, list) Type of atoms
    :param xcart: (numpy.ndarray) Cartesian positions
    :param znucl: (int, list) Atomic number for atoms in typat
    :return:
    """
    if isinstance(typat, int):
        lsttypat = [typat]
    else:
        lsttypat = typat
    if isinstance(znucl, (int, float)):
        lstznucl = [znucl]
    else:
        lstznucl = znucl

    covrad = [angstrom_bohr * covalent_radius(lstznucl[i - 1]) for i in lsttypat]
    bonds = []
    for t in range(len(xcart)):
        bonds1 = []
        for i in range(len(xcart[t])):
            for j in range(i + 1, len(xcart[t])):
                # print xcart[t][j]
                # print xcart[t][i]
                # Compute bond length between atoms i and j
                bl = math.sqrt(sum((xcart[t][j] - xcart[t][i]) ** 2))
                # print bl
                # print i,j
                # print covrad[i],covrad[j]
                if 1.35 * (covrad[i] + covrad[j]) > bl:
                    bonds1.append([i, j, bl, (xcart[t][j] - xcart[t][i]) / bl])
        bonds.append(bonds1)
    return bonds
Exemplo n.º 31
0
def compute_bonds(typat, xcart, znucl):
    """
    Compute the bond lengths of all the atoms
    inside the unitary box (NEEDS EXTENSION TO
    OUTSIDE THE BOX)
    """

    covrad = [angstrom_bohr * covalent_radius(znucl[i - 1]) for i in typat]
    bonds = []
    for t in range(len(xcart)):
        bonds1 = []
        for i in range(len(xcart[t])):
            for j in range(i + 1, len(xcart[t])):
                #print xcart[t][j]
                #print xcart[t][i]
                # Compute bond length between atoms i and j
                bl = math.sqrt(sum((xcart[t][j] - xcart[t][i]) ** 2))
                #print bl
                #print i,j
                #print covrad[i],covrad[j]
                if 1.35 * (covrad[i] + covrad[j]) > bl:
                    bonds1.append([i, j, bl, (xcart[t][j] - xcart[t][i]) / bl])
        bonds.append(bonds1)
    return bonds
Exemplo n.º 32
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
Exemplo n.º 33
0
    def move(self, entry_id, entry_jd, factor=0.2, in_place=False):

        st_orig = self.get_structure(entry_id)
        st_dest = self.get_structure(entry_jd)

        cm = ClusterMatch(st_orig, st_dest)
        cm.match()

        # pos_orig = np.array(entry_orig['structure']['positions']).reshape((-1, 3))
        # pos_dest = np.array(entry_dest['structure']['positions']).reshape((-1, 3))
        pos_orig = cm.structure1.positions
        pos_dest = cm.structure2.positions

        # Move to a position with negative energy
        reduc = 1
        new_positions = np.array(pos_orig)
        while True:
            new_positions = rotation_move(pos_orig,
                                          pos_dest,
                                          fraction=reduc * factor)
            new_structure = Structure(positions=new_positions,
                                      symbols=st_orig.symbols,
                                      periodicity=False)
            lj = LennardJones(new_structure)
            if lj.get_energy() < 0.0:
                break
            reduc -= 0.05
            pcm_log.debug(
                'Effective factor will be reduced to %7.3f, original factor %7.3f'
                % (reduc * factor, factor))
            if reduc <= 0.0:
                # print 'No movement effective'
                break

        # Avoid condition with atoms too close
        distance_matrix = scipy.spatial.distance_matrix(
            new_positions, new_positions)
        tmp = np.max(distance_matrix.flatten())
        # print 'Scaling by', tmp
        minimal_distance = np.min(
            (distance_matrix + tmp * np.eye(len(new_positions))).flatten())

        if minimal_distance < 1E-8:
            pcm_log.debug("Null distance between different atoms, no moving")
            new_positions = pos_orig

        if tmp > 5:
            # print 'Big scaling, better not to move'
            new_positions = pos_orig
        else:
            max_cov = np.max(covalent_radius(st_orig.symbols))
            new_positions *= max_cov / minimal_distance

        new_structure = Structure(positions=new_positions,
                                  symbols=st_orig.symbols,
                                  periodicity=False)
        # print 'Density of cluster', new_structure.density

        if in_place:
            self.unset_properties(entry_id)
            return self.set_structure(entry_id, new_structure)
        else:
            return self.new_entry(new_structure, active=False)
Exemplo n.º 34
0
    def hardness_old(self, noupdate=False, verbose=False, tolerance=0.05):
        """
        Calculates the hardness of a structure based in the model of XX
        We use the covalent radii from pychemia.utils.periodic.
        If noupdate=False
        the Laplacian matrix method is not used and rcut is 2*max(cov_radii)

        :param noupdate: (bool) If True, the Laplacian method is used
        :param verbose: (bool) To print some debug info
        :param tolerance: (float)

        :rtype : (float)
        """

        superc = self.structure.copy()
        superc.supercell(2, 2, 2)
        structure_analisys = StructureAnalysis(superc)

        natom = superc.natom
        volume = superc.volume

        max_covalent_radius = max(covalent_radius(superc.symbols))
        if verbose:
            print('Number of atoms', natom)
            print('Volume         ', volume)
            print('Covalent rad max', max_covalent_radius)
        rcut, coord, dis_dic = structure_analisys.get_bonds(
            2.0 * max_covalent_radius, noupdate, verbose, tolerance)

        sigma = 3.0
        c_hard = 1300.0
        x = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        dic_atms = {}
        for i in superc.symbols:
            dic_atms[i] = atomic_number(i)

        for i in dic_atms.keys():
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)
        f = 1.0 - (len(dic_atms) * f_n**(1.0 / len(dic_atms)) / f_d)**2

        if verbose:
            print('BONDS')
            print(dis_dic)
            print('COORDINATION')
            print(coord)

        for i in dis_dic.keys():
            i1 = dis_dic[i][2][0]
            i2 = dis_dic[i][2][1]

            ei = valence(superc.symbols[i1]) / covalent_radius(
                superc.symbols[i1])
            ej = valence(superc.symbols[i2]) / covalent_radius(
                superc.symbols[i2])

            sij = math.sqrt(ei * ej) / (coord[i1] * coord[i2]) / dis_dic[i][0]

            tot += dis_dic[i][1]
            x *= sij * dis_dic[i][1]

        if verbose:
            print("V:", volume)
            print("f:", f)
            print("x:", x)

        hardness_value = c_hard / volume * (
            len(dis_dic) * x**(1. / (len(dis_dic)))) * math.exp(-sigma * f)

        if verbose:
            print(hardness_value)

        return round(hardness_value, 3)
Exemplo n.º 35
0
    def hardness_OLD(self, noupdate=False, verbose=False, tolerance=0.05):
        """
        Calculates the hardness of a structure based in the model of XX
        We use the covalent radii from pychemia.utils.periodic.
        If noupdate=False
        the Laplacian matrix method is not used and rcut is 2*max(cov_radii)

        :param noupdate: (bool) If True, the Laplacian method is used
        :param verbose: (bool) To print some debug info
        :param tolerance: (float)

        :rtype : (float)
        """

        #from ase.data import covalent_radii

        #atms=atms.repeat([2,2,2])
        spc = self.copy()
        spc.supercell(2, 2, 2)
        natom = spc.natom
        volume = spc.volume

        #max_covalent_radius = max([covalent_radii[i.number] for i in atms])
        max_covalent_radius = max(covalent_radius(spc.symbols))
        if verbose:
            print('Number of atoms', natom)
            print('Volume         ', volume)
            print('Covalent rad max', max_covalent_radius)
        #rcut, coord, dis_dic  = get_bonds(atms,2.0*max_covalent_radius, noupdate,verbose,tolerance)
        rcut, coord, dis_dic = spc.get_bonds(2.0 * max_covalent_radius, noupdate, verbose, tolerance)

        sigma = 3.0
        c_hard = 1300.0
        x = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        dic_atms = {}
        #for i in atms:
        #    dic_atms[i.symbol] = i.number
        for i in spc.symbols:
            dic_atms[i] = atomic_number(i)

        #for i in dic_atms.keys():
        #    f_d += Z[i] / covalent_radii[dic_atms[i]]
        #    f_n *= Z[i] / covalent_radii[dic_atms[i]]
        #f = 1.0 - (len(dic_atms)*f_n**(1.0/len(dic_atms)) / f_d)**2

        for i in dic_atms.keys():
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)
        f = 1.0 - (len(dic_atms) * f_n ** (1.0 / len(dic_atms)) / f_d) ** 2

        if verbose:
            print 'BONDS'
            print dis_dic
            print 'COORDINATION'
            print coord

        for i in dis_dic.keys():
            i1 = dis_dic[i][2][0]
            i2 = dis_dic[i][2][1]

            #ei = Z[atms[i1].symbol] / covalent_radii[atms[i1].number]
            #ej = Z[atms[i2].symbol] / covalent_radii[atms[i2].number]
            ei = valence(spc.symbols[i1]) / covalent_radius(spc.symbols[i1])
            ej = valence(spc.symbols[i2]) / covalent_radius(spc.symbols[i2])


            #print 'bond ->', sqrt(ei * ej), (coord[i1] * coord[i2]), dis_dic[i][0]

            #        print atms[i1].symbol, ei, atms[i2].symbol, ej
            sij = sqrt(ei * ej) / (coord[i1] * coord[i2]) / dis_dic[i][0]
            #print 'sij', sij
            #print 'num_i_j_bonds', dis_dic[i][1]

            tot += dis_dic[i][1]
            x *= sij * dis_dic[i][1]
            #print 'x', x

        if verbose:
            print("V:", volume)
            print("f:", f)
            print("x:", x)

        #print 'len_bonds', len(dis_dic)
        #print 'hardness_value =', c_hard, volume, (len(dis_dic)), (  x ** (1. / (len(dis_dic)))), exp(-sigma * f)
        hardness_value = c_hard / volume * (len(dis_dic) * x ** (1. / (len(dis_dic)))) * exp(-sigma * f)

        if verbose:
            print hardness_value

        return round(hardness_value, 3)
Exemplo n.º 36
0
    def hardness(self, verbose=False, initial_cutoff_radius=0.8, ensure_conectivity=False, use_laplacian=True,
                 use_jump=True):
        """
        Calculates the hardness of a structure based in the model of XX
        We use the covalent radii from pychemia.utils.periodic.
        If noupdate=False
        the Laplacian matrix method is not used and rcut is 2*max(cov_radii)

        :param use_jump:
        :param ensure_conectivity:
        :param verbose: (bool) To print some debug info
        :param initial_cutoff_radius: (float)
        :param use_laplacian: (bool) If True, the Laplacian method is used

        :rtype : (float)
        """
        if self._supercell == (1, 1, 1) and verbose:
            print('''Only internal connectivity can be ensure, for complete connectivity in the crystal you must use a
                  supercell at of (2,2,2)''')

        bonds, coordination, all_distances, tolerances, cutoff_radius = \
            self.get_bonds_coordination(initial_cutoff_radius=initial_cutoff_radius,
                                        ensure_conectivity=ensure_conectivity,
                                        use_laplacian=use_laplacian, verbose=verbose, use_jump=use_jump)

        if verbose:
            print('Structure coordination : ', coordination)

        sigma = 3.0
        c_hard = 1300.0
        x = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        atomicnumbers = atomic_number(self.structure.species)

        if verbose:
            print('Atomic numbers in the structure :', atomicnumbers)

        for i in atomicnumbers:
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)

        # if verbose:
        # print 'fd', f_d
        #    print 'fn', f_n
        #    print atomicnumbers
        if f_d == 0:
            return 0.0
        f = 1.0 - (len(atomicnumbers) * f_n ** (1.0 / len(atomicnumbers)) / f_d) ** 2

        # Selection of different bonds
        diff_bonds = np.unique(np.array(reduce(lambda xx, y: xx + y, bonds)))
        if verbose:
            print('Number of different bonds : ', len(diff_bonds))

        for i in diff_bonds:
            i1 = all_distances[i]['pair'][0]
            i2 = all_distances[i]['pair'][1]

            ei = valence(self.structure.symbols[i1]) / covalent_radius(self.structure.symbols[i1])
            ej = valence(self.structure.symbols[i2]) / covalent_radius(self.structure.symbols[i2])
            # print 'bond ->', sqrt(ei * ej), (coordination[i1] * coordination[i2]), all_distances[i]['distance']

            sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / all_distances[i]['distance']
            num_i_j_bonds = len([j for j in diff_bonds if i1 in all_distances[j]['pair'] and
                                 i2 in all_distances[j]['pair']])
            # print 'sij', sij
            # print 'num_i_j_bonds', num_i_j_bonds
            tot += num_i_j_bonds
            x *= sij
            # print 'x', x

        vol = self.structure.volume
        if verbose:
            print("Structure volume:", vol)
            # print("f:", f)
            # print("x:", x)

        # print 'len_bonds', len(diff_bonds
        hardness_value = c_hard / vol * (len(diff_bonds) * x ** (1. / (len(diff_bonds)))) * math.exp(-sigma * f)

        return round(hardness_value, 3), cutoff_radius, coordination
Exemplo n.º 37
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
Exemplo n.º 38
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
Exemplo n.º 39
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
Exemplo n.º 40
0
    def get_bonds_coordination(self,
                               initial_cutoff_radius=0.8,
                               ensure_conectivity=False,
                               use_laplacian=True,
                               verbose=False,
                               tol=1E-15,
                               jump=0.01,
                               use_jump=True):
        """
        Computes simultaneously the bonds for all atoms and the coordination
        number using a multiplicative tolerance for the sum of covalent radius

        :param use_jump:
        :param jump:
        :param tol:
        :param verbose:
        :param use_laplacian:
        :param initial_cutoff_radius: (float) Tolerance factor (default is 1.2)
        :param ensure_conectivity: (bool) If True the tolerance of each bond is
               adjusted to ensure that each atom is connected at least once
        :return: tuple
        """
        if verbose:
            print('Computing all distances...')
        bonds_dict, distances_list = self.close_distances()
        if verbose:
            print('Number of distances computed: ', len(distances_list))

        cutoff_radius = initial_cutoff_radius
        bonds = None
        coordination = None
        tolerances = None

        while True:
            if verbose:
                print('Current cutoff radius : ', cutoff_radius)
            bonds = []
            tolerances = []
            for i in range(self.structure.natom):
                tole = cutoff_radius
                while True:
                    tmp_bonds = []
                    min_proportion = sys.float_info.max
                    for j in bonds_dict[str(i)]:
                        atom1 = self.structure.symbols[distances_list[j]
                                                       ['pair'][0]]
                        atom2 = self.structure.symbols[distances_list[j]
                                                       ['pair'][1]]
                        sum_covalent_radius = sum(
                            covalent_radius([atom1, atom2]))
                        distance = distances_list[j]['distance']
                        if distance == 0.0:
                            continue
                        proportion = distance / sum_covalent_radius
                        min_proportion = min(min_proportion, proportion)
                        if proportion <= tole:
                            tmp_bonds.append(j)
                    if len(tmp_bonds) == 0 and ensure_conectivity:
                        tole = min_proportion
                        cutoff_radius = tole
                    else:
                        bonds.append(tmp_bonds)
                        tolerances.append(min_proportion)
                        break

            if use_laplacian:
                size = (self.structure.natom, self.structure.natom)
                laplacian = np.zeros(size, dtype=np.int8)
                for listibonds in bonds:
                    for ibond in listibonds:
                        data = distances_list[ibond]
                        i = data['pair'][0]
                        j = data['pair'][1]
                        laplacian[i, j] = -1
                        laplacian[j, i] = -1
                        # print '%d %d' % (i,j)
                for i in range(self.structure.natom):
                    laplacian[i, i] = 0
                    laplacian[i, i] = -sum(laplacian[i])
                if verbose:
                    print(laplacian)
                if np.max(np.abs(laplacian)) == 0:
                    cutoff_radius += jump
                    if verbose:
                        print('The laplacian is all zero')
                        print('Increasing cutoff radius by ', jump, 'A\n')
                    continue

                # if verbose:
                # print laplacian
                # evals, evecs = scipy.sparse.linalg.eigsh(laplacian)
                ev = numpy.linalg.eigvalsh(laplacian)
                if verbose:
                    print('Number of Eigenvalues close to zero :',
                          sum(ev < tol))
                    print('Lowest Eigenvalues :', ev)
                    # print 'Lowest Eigenvalues :', evals

                if sum(ev < tol) > 1 and use_jump:
                    cutoff_radius += jump
                    if verbose:
                        print('Increasing cutoff radius by ', jump, 'A\n')
                else:
                    increase = False
                    for i in bonds:
                        if sum(i) == 0 and use_jump:
                            increase = True
                    if increase:
                        cutoff_radius += jump
                        if verbose:
                            print('Increasing cutoff radius by', jump, 'A\n')
                    else:
                        break
            else:
                break

        if bonds is not None:
            coordination = [len(x) for x in bonds]
        return bonds, coordination, distances_list, tolerances, cutoff_radius
Exemplo n.º 41
0
    def get_bonds_coordination(self, initial_cutoff_radius=0.8, ensure_conectivity=False, use_laplacian=True,
                               verbose=False, tol=1E-15, jump=0.01, use_jump=True):
        """
        Computes simultaneously the bonds for all atoms and the coordination
        number using a multiplicative tolerance for the sum of covalent radius

        :param use_jump:
        :param jump:
        :param tol:
        :param verbose:
        :param use_laplacian:
        :param initial_cutoff_radius: (float) Tolerance factor (default is 1.2)
        :param ensure_conectivity: (bool) If True the tolerance of each bond is
               adjusted to ensure that each atom is connected at least once
        :return: tuple
        """
        if verbose:
            print('Computing all distances...')
        bonds_dict, distances_list = self.close_distances()
        if verbose:
            print('Number of distances computed: ', len(distances_list))

        cutoff_radius = initial_cutoff_radius
        bonds = None
        coordination = None
        tolerances = None

        while True:
            if verbose:
                print('Current cutoff radius : ', cutoff_radius)
            bonds = []
            tolerances = []
            for i in range(self.structure.natom):
                tole = cutoff_radius
                while True:
                    tmp_bonds = []
                    min_proportion = sys.float_info.max
                    for j in bonds_dict[str(i)]:
                        atom1 = self.structure.symbols[distances_list[j]['pair'][0]]
                        atom2 = self.structure.symbols[distances_list[j]['pair'][1]]
                        sum_covalent_radius = sum(covalent_radius([atom1, atom2]))
                        distance = distances_list[j]['distance']
                        if distance == 0.0:
                            continue
                        proportion = distance / sum_covalent_radius
                        min_proportion = min(min_proportion, proportion)
                        if proportion <= tole:
                            tmp_bonds.append(j)
                    if len(tmp_bonds) == 0 and ensure_conectivity:
                        tole = min_proportion
                        cutoff_radius = tole
                    else:
                        bonds.append(tmp_bonds)
                        tolerances.append(min_proportion)
                        break

            if use_laplacian:
                size = (self.structure.natom, self.structure.natom)
                laplacian = np.zeros(size, dtype=np.int8)
                for listibonds in bonds:
                    for ibond in listibonds:
                        data = distances_list[ibond]
                        i = data['pair'][0]
                        j = data['pair'][1]
                        laplacian[i, j] = -1
                        laplacian[j, i] = -1
                        # print '%d %d' % (i,j)
                for i in range(self.structure.natom):
                    laplacian[i, i] = 0
                    laplacian[i, i] = -sum(laplacian[i])
                if verbose:
                    print(laplacian)
                if np.max(np.abs(laplacian)) == 0:
                    cutoff_radius += jump
                    if verbose:
                        print('The laplacian is all zero')
                        print('Increasing cutoff radius by ', jump, 'A\n')
                    continue

                # if verbose:
                # print laplacian
                # evals, evecs = scipy.sparse.linalg.eigsh(laplacian)
                ev = numpy.linalg.eigvalsh(laplacian)
                if verbose:
                    print('Number of Eigenvalues close to zero :', sum(ev < tol))
                    print('Lowest Eigenvalues :', ev)
                    # print 'Lowest Eigenvalues :', evals

                if sum(ev < tol) > 1 and use_jump:
                    cutoff_radius += jump
                    if verbose:
                        print('Increasing cutoff radius by ', jump, 'A\n')
                else:
                    increase = False
                    for i in bonds:
                        if sum(i) == 0 and use_jump:
                            increase = True
                    if increase:
                        cutoff_radius += jump
                        if verbose:
                            print('Increasing cutoff radius by', jump, 'A\n')
                    else:
                        break
            else:
                break

        if bonds is not None:
            coordination = [len(x) for x in bonds]
        return bonds, coordination, distances_list, tolerances, cutoff_radius
Exemplo n.º 42
0
    def hardness(self,
                 verbose=True,
                 initial_cutoff_radius=0.8,
                 ensure_conectivity=False,
                 use_laplacian=True,
                 use_jump=True,
                 tol=1E-15):
        """
        Calculates the hardness of a structure based in the model of XX
        We use the covalent radii from pychemia.utils.periodic.
        If noupdate=False
        the Laplacian matrix method is not used and rcut is 2*max(cov_radii)

        :param use_jump:
        :param ensure_conectivity:
        :param verbose: (bool) To print some debug info
        :param initial_cutoff_radius: (float)
        :param use_laplacian: (bool) If True, the Laplacian method is used
        :param tol: (float) Tolerance for considering two atoms bonded

        :rtype : (float)
        """
        if self._supercell == (1, 1, 1) and verbose:
            print(
                '''Only internal connectivity can be ensure, for complete connectivity in the crystal you must use a
                  supercell at of (2,2,2)''')

        bonds, coordination, all_distances, tolerances, cutoff_radius = \
            self.get_bonds_coordination(initial_cutoff_radius=initial_cutoff_radius,
                                        ensure_conectivity=ensure_conectivity,
                                        use_laplacian=use_laplacian, verbose=verbose, use_jump=use_jump, tol=tol)

        if verbose:
            print('Structure coordination : ', coordination)

        sigma = 3.0
        c_hard = 1300.0
        x = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        atomicnumbers = atomic_number(self.structure.species)

        if verbose:
            print('Atomic numbers in the structure :', atomicnumbers)

        for i in atomicnumbers:
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)

        # if verbose:
        # print 'fd', f_d
        #    print 'fn', f_n
        #    print atomicnumbers
        if f_d == 0:
            return 0.0
        f = 1.0 - (len(atomicnumbers) * f_n**(1.0 / len(atomicnumbers)) /
                   f_d)**2

        # Selection of different bonds
        diff_bonds = np.unique(
            np.array(functools.reduce(lambda xx, y: xx + y, bonds)))
        if verbose:
            print('Number of different bonds : ', len(diff_bonds))

        for i in diff_bonds:
            i1 = all_distances[i]['pair'][0]
            i2 = all_distances[i]['pair'][1]

            ei = valence(self.structure.symbols[i1]) / covalent_radius(
                self.structure.symbols[i1])
            ej = valence(self.structure.symbols[i2]) / covalent_radius(
                self.structure.symbols[i2])
            # print 'bond ->', sqrt(ei * ej), (coordination[i1] * coordination[i2]), all_distances[i]['distance']

            sij = math.sqrt(ei * ej) / (coordination[i1] * coordination[i2]
                                        ) / all_distances[i]['distance']
            num_i_j_bonds = len([
                j for j in diff_bonds if i1 in all_distances[j]['pair']
                and i2 in all_distances[j]['pair']
            ])
            # print 'sij', sij
            # print 'num_i_j_bonds', num_i_j_bonds
            tot += num_i_j_bonds
            x *= sij
            # print 'x', x

        vol = self.structure.volume
        if verbose:
            print("Structure volume:", vol)
            # print("f:", f)
            # print("x:", x)

        # print 'len_bonds', len(diff_bonds
        hardness_value = c_hard / vol * (
            len(diff_bonds) * x**(1. /
                                  (len(diff_bonds)))) * math.exp(-sigma * f)

        return round(hardness_value, 3), cutoff_radius, coordination
Exemplo n.º 43
0
    def hardness_old(self, noupdate=False, verbose=False, tolerance=0.05):
        """
        Calculates the hardness of a structure based in the model of XX
        We use the covalent radii from pychemia.utils.periodic.
        If noupdate=False
        the Laplacian matrix method is not used and rcut is 2*max(cov_radii)

        :param noupdate: (bool) If True, the Laplacian method is used
        :param verbose: (bool) To print some debug info
        :param tolerance: (float)

        :rtype : (float)
        """

        superc = self.structure.copy()
        superc.supercell(2, 2, 2)
        structure_analisys = StructureAnalysis(superc)

        natom = superc.natom
        volume = superc.volume

        max_covalent_radius = max(covalent_radius(superc.symbols))
        if verbose:
            print('Number of atoms', natom)
            print('Volume         ', volume)
            print('Covalent rad max', max_covalent_radius)
        rcut, coord, dis_dic = structure_analisys.get_bonds(2.0 * max_covalent_radius, noupdate, verbose, tolerance)

        sigma = 3.0
        c_hard = 1300.0
        x = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        dic_atms = {}
        for i in superc.symbols:
            dic_atms[i] = atomic_number(i)

        for i in dic_atms.keys():
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)
        f = 1.0 - (len(dic_atms) * f_n ** (1.0 / len(dic_atms)) / f_d) ** 2

        if verbose:
            print('BONDS')
            print(dis_dic)
            print('COORDINATION')
            print(coord)

        for i in dis_dic.keys():
            i1 = dis_dic[i][2][0]
            i2 = dis_dic[i][2][1]

            ei = valence(superc.symbols[i1]) / covalent_radius(superc.symbols[i1])
            ej = valence(superc.symbols[i2]) / covalent_radius(superc.symbols[i2])

            sij = math.sqrt(ei * ej) / (coord[i1] * coord[i2]) / dis_dic[i][0]

            tot += dis_dic[i][1]
            x *= sij * dis_dic[i][1]

        if verbose:
            print("V:", volume)
            print("f:", f)
            print("x:", x)

        hardness_value = c_hard / volume * (len(dis_dic) * x ** (1. / (len(dis_dic)))) * math.exp(-sigma * f)

        if verbose:
            print(hardness_value)

        return round(hardness_value, 3)
Exemplo n.º 44
0
    def hardness(self, noupdate=False, verbose=False, tolerance=1):
        """
        Calculates the hardness of a structure based in the model of XX
        We use the covalent radii from pychemia.utils.periodic.
        If noupdate=False
        the Laplacian matrix method is not used and rcut is 2*max(cov_radii)

        :param noupdate: (bool) If True, the Laplacian method is used
        :param verbose: (bool) To print some debug info
        :param tolerance: (float)

        :rtype : (float)
        """

        bonds, coordination, all_distances, tolerances = self.get_bonds_coordination(tolerance=tolerance, ensure_conectivity=True)

        if verbose:
            print 'BONDS'
            print bonds
            print 'COORDINATION'
            print coordination

        sigma = 3.0
        c_hard = 1300.0
        x = 1.
        tot = 0.0
        f_d = 0.0
        f_n = 1.0
        atomicnumbers = atomic_number(self.get_composition().species)

        if verbose:
            print atomicnumbers

        for i in atomicnumbers:
            f_d += valence(i) / covalent_radius(i)
            f_n *= valence(i) / covalent_radius(i)
        f = 1.0 - (len(atomicnumbers) * f_n ** (1.0 / len(atomicnumbers)) / f_d) ** 2

        # Selection of different bonds
        diff_bonds = _np.unique(_np.array(reduce(lambda x, y: x+y, bonds)))
        for i in diff_bonds:
            i1 = all_distances[i]['pair'][0]
            i2 = all_distances[i]['pair'][1]

            ei = valence(self.symbols[i1]) / covalent_radius(self.symbols[i1])
            ej = valence(self.symbols[i2]) / covalent_radius(self.symbols[i2])
            #print 'bond ->', sqrt(ei * ej), (coordination[i1] * coordination[i2]), all_distances[i]['distance']

            sij = sqrt(ei * ej) / (coordination[i1] * coordination[i2]) / all_distances[i]['distance']
            num_i_j_bonds = len([j for j in diff_bonds if i1 in all_distances[j]['pair'] and i2 in all_distances[j]['pair']])
            #print 'sij', sij
            #print 'num_i_j_bonds', num_i_j_bonds
            tot += num_i_j_bonds
            x *= sij
            #print 'x', x

        if verbose:
            print("V:", self.volume)
            print("f:", f)
            print("x:", x)

        #print 'len_bonds', len(diff_bonds)
        #print 'hardness_value =', c_hard, self.volume, (len(diff_bonds)), ( x ** (1. / (len(diff_bonds)))), exp(-sigma * f)
        hardness_value = c_hard / self.volume * (len(diff_bonds) * x ** (1. / (len(diff_bonds)))) * exp(-sigma * f)

        if verbose:
            print hardness_value

        return round(hardness_value, 3)