Exemple #1
0
    def move(self, entry_id, entry_jd, factor=0.2, in_place=False):
        """
        Moves entry_id in the direction of entry_jd
        If in_place is True the movement occurs on the
        same address as entry_id

        :param factor:
        :param entry_id:
        :param entry_jd:
        :param in_place:
        :return:
        """
        structure_mobile = self.get_structure(entry_id)
        structure_target = self.get_structure(entry_jd)

        if structure_mobile.natom != structure_target.natom:
            # Moving structures with different number of atoms is only implemented for smaller structures moving
            # towards bigger ones by making a super-cell and only if their size is smaller that 'max_comp_mult'

            mult1 = structure_mobile.get_composition().gcd
            mult2 = structure_target.get_composition().gcd
            lcd = mult1 * mult2 / gcd(mult1, mult2)
            if lcd > self.max_comp_mult:
                # The resulting structure is bigger than the limit
                # cannot move
                if not in_place:
                    return self.new_entry(structure_mobile)
                else:
                    return entry_id

        # We will move structure1 in the direction of structure2
        match = StructureMatch(structure_target, structure_mobile)
        match.match_size()
        match.match_shape()
        match.match_atoms()
        displacements = match.reduced_displacement()

        new_reduced = match.structure2.reduced + factor * displacements
        new_cell = match.structure2.cell
        new_symbols = match.structure2.symbols
        new_structure = Structure(reduced=new_reduced,
                                  symbols=new_symbols,
                                  cell=new_cell)
        if in_place:
            return self.set_structure(entry_id, new_structure)
        else:
            return self.new_entry(new_structure, active=False)
Exemple #2
0
 def __init__(self):
     Codes.__init__(self)
     self.workdir = None
     self.geometry = {}
     self.driver = {}
     self.hamiltonian = {}
     self.options = {}
     self.analysis = {}
     self.parser_options = {}
     self.slater_koster = []
     self.structure = Structure()
     self.binary = 'dftb+'
     self.runner = None
     self.kpoints = None
     self.stdout_file = None
     self.output = None
     self.kp_density = None
Exemple #3
0
def spglib_version():
    from pychemia import Structure
    from . import CrystalSymmetry

    # Testing version of spglib
    st = Structure(symbols=['H'])
    symm = CrystalSymmetry(st)
    ret = spg.spglib.spg.dataset(symm.transposed, symm.reduced, symm.numbers,
                                 1e-5, -1.0)
    if type(ret[3]) is list:
        HAS_SPGLIB = False
        version = "%d.%d.%d" % spg.get_version()
        print('SPGLIB current version is %s, please install spglib > 1.9' %
              version)
    else:
        HAS_SPGLIB = True
    return HAS_SPGLIB
Exemple #4
0
    def __init__(self, workdir='.'):

        if not os.path.lexists(workdir):
            os.mkdir(workdir)

        CodeRun.__init__(self, executable='dftb+', workdir=workdir)
        self.geometry = {}
        self.driver = {}
        self.hamiltonian = {}
        self.options = {}
        self.analysis = {}
        self.parser_options = {}
        self.slater_koster = []
        self.structure = Structure()
        self.runner = None
        self.kpoints = None
        self.stdout_file = None
        self.output = None
        self.kp_density = None
Exemple #5
0
def Al2O3():
    return Structure(symbols=[
        'Al', 'Al', 'Al', 'Al', 'Al', 'Al', 'Al', 'Al', 'Al', 'Al', 'Al', 'Al',
        'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O',
        'O', 'O', 'O', 'O'
    ],
                     cell=[[4.807634, 0.0, 0.0], [-2.403817, 4.163534, 0.0],
                           [0.0, 0.0, 13.11727]],
                     reduced=[[0.0, 0.0, 0.352185],
                              [0.666667, 0.333333, 0.685518],
                              [0.333333, 0.666667, 0.018852],
                              [0.0, 0.0, 0.647815],
                              [0.666667, 0.333333, 0.981148],
                              [0.333333, 0.666667, 0.314482],
                              [0.0, 0.0, 0.147815],
                              [0.666667, 0.333333, 0.481148],
                              [0.333333, 0.666667, 0.814482],
                              [0.0, 0.0, 0.852185],
                              [0.666667, 0.333333, 0.185518],
                              [0.333333, 0.666667, 0.518852],
                              [0.306167, 0.0, 0.25],
                              [0.972834, 0.333333, 0.583333],
                              [0.639501, 0.666667, 0.916667],
                              [0.693833, 0.0, 0.75],
                              [0.360499, 0.333333, 0.083333],
                              [0.027166, 0.666667, 0.416667],
                              [0.0, 0.306167, 0.25],
                              [0.666667, 0.639501, 0.583333],
                              [0.333333, 0.972834, 0.916667],
                              [0.0, 0.693833, 0.75],
                              [0.666667, 0.027166, 0.083333],
                              [0.333333, 0.360499, 0.416667],
                              [0.693833, 0.693833, 0.25],
                              [0.360499, 0.027166, 0.583333],
                              [0.027166, 0.360499, 0.916667],
                              [0.306167, 0.306167, 0.75],
                              [0.972834, 0.639501, 0.083333],
                              [0.639501, 0.972834, 0.416667]],
                     periodicity=True)
Exemple #6
0
def movement_sweep(pos_orig, pos_dest, symbols, figname='figure.pdf'):
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots(ncols=1, nrows=3, sharex=True, figsize=(11, 8.5))
    plt.subplots_adjust(left=0.07,
                        bottom=0.07,
                        right=0.98,
                        top=0.98,
                        wspace=0.08,
                        hspace=0.08)

    ee = []
    ff = []
    dd = []
    delta = 2E-3
    xx = np.arange(0.0, 1.0 + 0.9 * delta, delta)

    for f in xx:
        new_positions = direct_move(pos_orig, pos_dest, fraction=f)

        new_structure = Structure(positions=new_positions,
                                  symbols=symbols,
                                  periodicity=False)
        lj = LennardJones(new_structure)
        ee.append(lj.get_energy())
        ff.append(np.max(lj.get_magnitude_forces()))
        # Distance Matrix
        dm = scipy.spatial.distance_matrix(new_positions, new_positions)
        # Min distance
        md = np.min(
            np.array(np.array(dm) + 100 * np.eye(len(pos_orig))).flatten())
        dd.append(md)

    ax[0].plot(xx, ee)
    ax[0].set_ylim(min(ee), 0.1)
    ax[1].semilogy(xx, ff)
    ax[2].plot(xx, dd)

    st = Structure(positions=pos_orig, symbols=symbols, periodicity=False)
    lj = LennardJones(st)
    ax[0].plot(0, lj.get_energy(), 'ro')
    ax[1].semilogy(0, np.max(lj.get_magnitude_forces()), 'ro')
    dm = scipy.spatial.distance_matrix(lj.structure.positions,
                                       lj.structure.positions)
    md = np.min(np.array(np.array(dm) + 100 * np.eye(len(pos_orig))).flatten())
    ax[2].plot(0, md, 'ro')

    st = Structure(positions=pos_dest, symbols=symbols, periodicity=False)
    lj = LennardJones(st)
    ax[0].plot(1, lj.get_energy(), 'ro')

    ax[1].semilogy(1, np.max(lj.get_magnitude_forces()), 'ro')
    dm = scipy.spatial.distance_matrix(lj.structure.positions,
                                       lj.structure.positions)
    md = np.min(np.array(np.array(dm) + 100 * np.eye(len(pos_orig)).flatten()))
    ax[2].plot(1, md, 'ro')

    ax[2].set_xlim(-0.01, 1.01)

    ax[0].set_ylabel('Energy')
    ax[1].set_ylabel('Max Force')
    ax[2].set_ylabel('Minimal inter atomic distance')

    plt.savefig(figname)
Exemple #7
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)
Exemple #8
0
def read_poscar(path='POSCAR'):
    """
    Load a POSCAR file and return a pychemia structure object

    :param path: (str) Path to a POSCAR file or a directory where a file named 'POSCAR' is located
    :return:
    """
    # The argument 'path' could refer to a POSCAR file or the directory where the file 'POSCAR' exists
    if os.path.isfile(path):
        poscarfile = path
        if os.path.dirname(path) != '':
            potcarfile = os.path.dirname(path) + os.sep + 'POTCAR'
        else:
            potcarfile = 'POTCAR'
    elif os.path.isdir(path) and os.path.isfile(path + os.sep + 'POSCAR'):
        poscarfile = path + os.sep + 'POSCAR'
        potcarfile = path + os.sep + 'POTCAR'
    else:
        raise ValueError("ERROR: No POSCAR file found on %s" % path)

    # Reading the POSCAR file
    rf = open(poscarfile, 'r')
    comment = rf.readline().strip()
    latconst = float(rf.readline().split()[0])
    newcell = zeros((3, 3))

    newcell[0, :] = latconst * array(
        [float(x) for x in rf.readline().split()[:3]])
    newcell[1, :] = latconst * array(
        [float(x) for x in rf.readline().split()[:3]])
    newcell[2, :] = latconst * array(
        [float(x) for x in rf.readline().split()[:3]])

    line = rf.readline()
    species = None

    # This is the old format, the only way of knowing which species are refering is by
    # reading the POTCAR file
    natom_per_species = array([int(x) for x in line.split() if x.isdigit()])

    # Check if the file is the new format, in such case this line contains the
    # atomic symbols of the atoms and the next line the number of atoms of each
    # species. The new format makes a POSCAR self-contained to create a structure
    if len(natom_per_species) == 0:
        species = [x for x in line.split() if x in atomic_symbols]
        line = rf.readline()
        natom_per_species = array(
            [int(x) for x in line.split() if x.isdigit()])

    natom = sum(natom_per_species)

    if species is None:
        comment_species = [x for x in comment.split() if x in atomic_symbols]
        if os.path.isfile(potcarfile):
            species = get_species(potcarfile)
        elif len(comment_species) == len(natom_per_species):
            species = comment_species
        else:
            raise ValueError(
                "ERROR: The POSCAR does not have information about the species present on the structure\n"
                +
                "You can set a consistent POTCAR along the POSCAR or modify your POSCAR to the\n"
                +
                "new format by adding the atomic symbol(s) on the sixth line of the file"
            )

    symbols = []
    for i in range(len(natom_per_species)):
        for j in range(natom_per_species[i]):
            symbols.append(species[i])

    mode = rf.readline()
    if mode[0].lower() in ['c', 'k']:
        kmode = 'Cartesian'
    else:
        kmode = 'Direct'

    pos = []
    for i in range(natom):
        pos += [float(x) for x in rf.readline().split()[:3]]
    pos = array(pos).reshape((-1, 3))

    if kmode == 'Cartesian':
        return Structure(cell=newcell,
                         symbols=symbols,
                         positions=pos,
                         comment=comment)
    else:
        return Structure(cell=newcell,
                         symbols=symbols,
                         reduced=pos,
                         comment=comment)
Exemple #9
0
    def get_simple_match(self):

        self.get_minimal_splitting()

        # grp1 and grp2 are tuples where the first value is the dimension of cut and the second one
        # is the second one is the index for the plane cut
        grp0 = self.ss_tags[0]
        grp1 = self.ss_tags[1]

        idim1 = grp0[0]
        idim2 = grp1[0]
        cp1 = grp0[1]
        cp2 = grp1[1]

        cut_value1 = self.cut_planes[0][idim1][cp1]
        cut_value2 = self.cut_planes[1][idim2][cp2]

        print('idim1:', idim1, 'cut_value1:', cut_value1)
        print('idim2:', idim2, 'cut_value2:', cut_value2)

        # Select one possible permutation that will make the second
        # structure being cutted along the same dimension as the first one
        permsel1 = None
        permsel2 = None
        for i in itertools.permutations(range(3), 3):
            if i[idim1] == idim2:
                permsel1 = i
            if i[idim2] == idim1:
                permsel2 = i
            if permsel1 is not None and permsel2 is not None:
                break

        print('Permutation Selected 1:', permsel1)
        print('Permutation Selected 2:', permsel2)

        newreduced1 = np.zeros((self.structures[0].natom, 3))
        newreduced2 = np.zeros((self.structures[1].natom, 3))
        symbols1 = self.structures[0].natom * ['U']
        symbols2 = self.structures[1].natom * ['U']

        nsites = self.structures[0].nsites

        index1 = 0
        index2 = 0

        for i in range(nsites):
            if i in self.split_sites[0][grp0]:
                newreduced1[index1] = self.structures[0].reduced[i, :]
                symbols1[index1] = self.structures[0].symbols[i]
                index1 += 1
            else:
                pos = self.structures[0].reduced[i, permsel1]
                # print i,' - ', self.structures[0].reduced[i], '==>', pos
                newreduced2[index2] = pos
                symbols2[index2] = self.structures[0].symbols[i]
                index2 += 1

        # print '1 Reduced\n', newreduced1
        # print '2 Reduced\n', newreduced2

        # print '1 Symbols:', symbols1
        # print '2 Symbols:', symbols2

        for i in range(nsites):
            if i in self.split_sites[1][grp1]:
                newreduced2[index2] = self.structures[1].reduced[i, :]
                symbols2[index2] = self.structures[1].symbols[i]
                index2 += 1
            else:
                pos = self.structures[1].reduced[i, permsel1]
                # print i,' - ', self.structures[1].reduced[i], '==>', pos
                newreduced1[index1] = pos
                symbols1[index1] = self.structures[1].symbols[i]
                index1 += 1

        cell1 = np.array(self.structures[0].cell)
        cell2 = np.array(self.structures[1].cell)

        # The Splitting is not checking for right stochiometry right now
        # Reverting the symbols to the original ones
        symbols1 = self.structures[0].symbols
        symbols2 = self.structures[1].symbols

        newst1 = Structure(symbols=symbols1, reduced=newreduced1, cell=cell1)
        newst2 = Structure(symbols=symbols2, reduced=newreduced2, cell=cell2)

        return newst1, newst2
Exemple #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(("Initail composition: %s" % comp))
        print((Composition(comp)))
        print((Composition(comp).symbols))
        for i in comp:
            comp[i] *= factor
        new_comp = Composition(comp)
        for i in range(len(new_comp.symbols)):
            if new_comp.symbols[i] == "Mg":
                new_comp.symbols[i] = "Ca"
            else:
                new_comp.symbols[i] = "Mg"
        print((new_comp.symbols))

        print(
            "###############################################################")
        print(("New comp symbols= ", new_comp.symbols))
        print(
            "###############################################################")

        while True:
            rnd = random.random()
            condition = {
                'structure.nspecies': new_comp.nspecies,
                'structure.natom': new_comp.natom
            }
            if self.pcdb_source is None:
                rnd = 0
            if 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
Exemple #11
0
 def get_new_structure(self, spglib_cell):
     from pychemia import Structure
     cell = spglib_cell[0]
     reduced = spglib_cell[1]
     symbols = [self.structure.species[x - 1] for x in spglib_cell[2]]
     return Structure(cell=cell, reduced=reduced, symbols=symbols)
Exemple #12
0
def Cr():
    return Structure(symbols=['Cr', 'Cr'],
                     cell=2.812697,
                     reduced=[[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]],
                     periodicity=True)