Beispiel #1
0
    def move_random(self, entry_id, factor=0.2, in_place=False, kind='move'):

        entry = self.get_entry(entry_id)
        pos = np.array(entry['structure']['positions']).reshape((-1, 3))
        # Unit Vectors
        uv = pychemia.utils.mathematics.unit_vectors(
            2 * np.random.rand(*pos.shape) - 1)
        new_pos = generic_serializer(pos + factor * uv)

        structure = pychemia.Structure(positions=new_pos,
                                       symbols=entry['structure']['symbols'],
                                       periodicity=False)

        if in_place:
            return self.pcdb.db.pychemia_entries.update_one(
                {'_id': entry_id},
                {'$set': {
                    'structure': structure.to_dict,
                    'properties': {}
                }})
        else:
            structure = pychemia.Structure(
                positions=new_pos,
                symbols=entry['structure']['symbols'],
                periodicity=False)
            return self.new_entry(structure, active=False)
Beispiel #2
0
    def cross(self, ids):
        if len(ids) != 2:
            raise ValueError("Crossing only implemented between two clusters")

        entry0 = self.get_entry(ids[0])
        entry1 = self.get_entry(ids[1])

        pos0 = np.array(entry0['structure']['positions']).reshape((-1, 3))
        pos1 = np.array(entry1['structure']['positions']).reshape((-1, 3))

        cut = np.random.randint(1, len(pos0))

        new_pos0 = np.concatenate((pos0[:cut], pos1[cut:]))
        new_pos1 = np.concatenate((pos1[:cut], pos0[cut:]))

        new_structure = pychemia.Structure(
            positions=new_pos0,
            symbols=entry0['structure']['symbols'],
            periodicity=False)
        entry_id = self.new_entry(structure=new_structure)
        new_structure = pychemia.Structure(
            positions=new_pos1,
            symbols=entry0['structure']['symbols'],
            periodicity=False)
        entry_jd = self.new_entry(structure=new_structure)

        return entry_id, entry_jd
Beispiel #3
0
def get_onion_layers(structure):
    """
    Returns the different layers of a finite structure

    :param structure:
    :return:
    """
    assert (not structure.is_periodic)
    layers = []
    cur_st = structure.copy()

    morelayers = True
    while morelayers:
        pos = cur_st.positions
        if len(pos) <= 4:
            core = range(cur_st.natom)
            layers.append(core)
            break

        st = pychemia.Structure(positions=pos, symbols=len(pos)*['H'], periodicity=False)
        st.canonical_form()
        # print('The current volume is %7.3f' % st.volume)
        if st.volume < 0.1:
            core = range(cur_st.natom)
            layers.append(core)
            break

        try:
            voro = scipy.spatial.Voronoi(pos)
            surface = [i for i in range(cur_st.natom) if -1 in voro.regions[voro.point_region[i]]]
        except qhull.QhullError:
            surface = range(cur_st.natom)
            morelayers = False
        layers.append(surface)
        if not morelayers:
            break
        core = [i for i in range(cur_st.natom) if i not in surface]
        if len(core) == 0:
            break
        symbols = list(np.array(cur_st.symbols)[np.array(core)])
        positions = cur_st.positions[np.array(core)]
        cur_st = pychemia.Structure(symbols=symbols, positions=positions, periodicity=False)
    new_layers = [layers[0]]
    included = list(layers[0])
    acumulator = 0
    for i in range(1, len(layers)):
        noincluded = [j for j in range(structure.natom) if j not in included]
        # print 'Layer: %3d   Atoms on Surface: %3d     Internal Atoms: %3d' % (i,
        #                                                                      len(included) - acumulator,
        #                                                                      len(noincluded))
        acumulator = len(included)
        relabel = [noincluded[j] for j in layers[i]]
        included += relabel
        new_layers.append(relabel)

    return new_layers
Beispiel #4
0
def random_attaching(structure, seed, target_species, natom_crystal, radius=1.8, basetol=4.0):

    lys = pychemia.analysis.surface.get_onion_layers(structure)
    surface = lys[0]

    counter = 0
    while True:
        if seed not in surface or counter > 0:
            print('Current Seed not in surface, searching a new seed')
            seed = find_new_seed(structure, surface, seed, natom_crystal)

        tol = basetol
        facets = []
        while True:
            facets, mintol = get_facets(structure, surface, seed, distance_tolerance=tol)
            if len(facets) > 0:
                print('Possible Facets', facets)
                break
            elif mintol > 2 * basetol:
                return None, None, None, None
            else:
                tol = mintol
                print('No facets found, increasing tolerance to ', tol)

        counter = 0
        while True:
            counter += 1
            rnd = np.random.randint(len(facets))
            facet_chosen = facets[rnd]
            print('Seed: %3d     Number of facets: %3d     Facet chosen: %s' % (seed, len(facets), facet_chosen))

            center, uvector, atoms_facet = attach_to_facet(structure, facet_chosen)

            new_sts = {}
            good_pos = 0
            for specie in target_species:
                cov_rad = pychemia.utils.periodic.covalent_radius(specie)
                vec = center + radius * cov_rad * uvector
                new_symbols = list(structure.symbols) + [specie]
                new_positions = np.concatenate((structure.positions, [vec]))

                dist_matrix = scipy.spatial.distance_matrix(new_positions, new_positions)
                identity = np.eye(len(new_positions), len(new_positions))
                mindist = np.min((dist_matrix + 100 * identity).flatten())
                if mindist > cov_rad:
                    good_pos += 1
                    print('We have a minimal distance of', mindist)
                new_sts[specie] = pychemia.Structure(symbols=new_symbols, positions=new_positions, periodicity=False)

            if good_pos == len(target_species):
                print('Good position selected for all species')
                break
            else:
                print('No enough good positions: %d. One bad position, choosing a new facet' % good_pos)
                if counter > len(facets):
                    break
        if good_pos == len(target_species):
            break
    return new_sts, facet_chosen, center, uvector
Beispiel #5
0
def run_one(a):
    """
    Take one OQMD 'Entry' object, search all the calculations associated and take the best calculation
    in order to insert its data into the PyChemia Database

    :param a: OQMD Entry object
    :return:
    """
    print('Entry: %6d  Number of Calculations: %3d  Energies: %s' %
          (a.id, a.calculation_set.count(),
           str([c.energy for c in a.calculation_set.all()])))
    energy = 1E10
    best_calculation = None
    for c in a.calculation_set.all():
        if c.energy is not None and c.energy < energy:
            best_calculation = c
            energy = c.energy

    if best_calculation is None:
        return None, None

    cell = best_calculation.output.cell.T
    symbols = atomic_symbol(best_calculation.output.atomic_numbers)
    reduced = best_calculation.output.coords

    structure = pychemia.Structure(cell=cell, symbols=symbols, reduced=reduced)
    structure_id = best_calculation.output_id
    entry_id = a.id
    calculation_id = best_calculation.id
    energy_pa = best_calculation.energy_pa
    energy = best_calculation.energy
    band_gap = best_calculation.band_gap
    settings = best_calculation.settings
    try:
        spacegroup_number = best_calculation.output.spacegroup.number
    except ValueError:
        spacegroup_number = None

    symm = pychemia.crystal.CrystalSymmetry(structure)
    sym2 = symm.number(1E-2)

    properties = {
        'oqmd': {
            'structure_id': structure_id,
            'entry_id': entry_id,
            'calculation_id': calculation_id,
            'energy_pa': energy_pa,
            'energy': energy,
            'band_gap': band_gap,
            'settings': settings,
            'spacegroup_number': spacegroup_number
        },
        'spacegroup_number': {
            'value': sym2,
            'symprec': 1E-2
        }
    }

    return structure, properties
Beispiel #6
0
    def run(self, nparal=4):

        for ifactor in np.arange(self.ini_factor, self.fin_factor + 0.9 * self.delta_factor, self.delta_factor):

            lattice = self.structure.lattice
            new_lengths = (ifactor - 1.0) * np.array(self.expansion) * lattice.lengths + lattice.lengths
            newlattice_params = tuple(np.concatenate(new_lengths, lattice.angles))
            newlattice = pychemia.crystal.Lattice.from_parameters_to_cell(*newlattice_params)
            newst = pychemia.Structure(cell=newlattice.cell, symbols=self.structure.symbols,
                                       reduced=self.structure.reduced)

            tmpkp = pychemia.crystal.KPoints.optimized_grid(newst.lattice, kp_density=self.kp_density, force_odd=True)

            if ifactor < 1.0:
                print('\nCompresing cell to %7.3f percent' % (ifactor * 100))
                print('-------------------\n')
            elif ifactor > 1.0:
                print('\nExpanding cell to %7.3f percent' % (ifactor * 100))
                print('-------------------\n')
            else:
                print('\nOriginal cell')
                print('-------------\n')

            new_density = tmpkp.get_density_of_kpoints(newst.lattice)
            print('KP Density: target: %d  new lattice: %d' % (self.kp_density, new_density))
            print('KP Grid:    target: %s  new lattice: %s' % (self.kpoints.grid, tmpkp.grid))

            if np.prod(tmpkp.grid) > np.prod(self.kpoints.grid):

                print('The new cell ask for a bigger grid, doing a new convergence...\n')

                self.cleaner()
                print('\nConvergence of K-Point Grid')
                print('---------------------------\n')
                ck = ConvergenceKPointGrid(newst, workdir=self.workdir + os.sep + 'KPCONV_' + str(ifactor),
                                           executable=self.executable, encut=self.encut, energy_tolerance=self.energy_tol,
                                           recover=True)
                ck.run(nparal=nparal)
                ck.save()
                ck.report()
                self.kpoints = ck.best_kpoints
            else:
                print('The current grid is still good')

            self.cleaner()
            relax = IonRelaxation(structure=newst, workdir=self.workdir + os.sep + 'RELAX_' + str(ifactor),
                                  kp_grid=self.kpoints.grid, encut=self.encut,
                                  relax_cell=False, target_forces=self.target_forces, waiting=False,
                                  executable=self.executable)
            relax.run(nparal=nparal)

            vo = pychemia.code.vasp.VaspOutput(self.workdir + '_' + str(ifactor) + '/OUTCAR')
            relst = relax.get_final_geometry()
            symm = pychemia.symm.StructureSymmetry(relst)

            self.output.append({'factor': ifactor, 'volume': newst.volume, 'density': newst.density,
                                'grid': list(self.kpoints.grid), 'output': vo.to_dict, 'spacegroup': symm.number()})
            self.save()
Beispiel #7
0
def ase2pychemia(aseatoms):
    """
    Converts an ase atoms object into a pychemia
    structure object
    """
    cell = aseatoms.get_cell()
    an = aseatoms.get_atomic_numbers()
    symbols = pychemia.utils.periodic.atomic_symbol(an)
    positions = aseatoms.get_positions()
    return pychemia.Structure(cell=cell, positions=positions, symbols=symbols)
Beispiel #8
0
def test_gold():
    """
    Visualization of Gold FCC lattice   :
    """
    a = 4.05
    b = a / 2
    fcc = pychemia.Structure(symbols=['Au'], cell=[[0, b, b], [b, 0, b], [b, b, 0]], periodicity=True)
    assert (fcc.natom == 1)
    assert (fcc.is_periodic is True)
    assert (fcc.is_crystal is True)
    fig = fcc.plot()
    time.sleep(5)
    fig.remove()
    fig.stop()
Beispiel #9
0
 def test_structure(self):
     """
     Test (pychemia.core.structure)                              :
     """
     a = 4.05
     b = a / 2
     fcc = pychemia.Structure(symbols=['Au'],
                              cell=[[0, b, b], [b, 0, b], [b, b, 0]],
                              periodicity=True)
     self.assertEqual(fcc.natom, 1)
     fcc_copy = fcc.copy()
     fcc_copy.canonical_form()
     self.assertTrue(abs(fcc.volume - fcc_copy.volume) < 1E-13)
     self.assertTrue(
         np.linalg.norm(fcc_copy.lattice.angles -
                        fcc.lattice.angles) < 1E-10)
     spc = fcc.supercell((3, 3, 3))
     self.assertEqual(spc.natom, 27)
Beispiel #10
0
def test_structure():
    """
    Tests (pychemia.core.structure)                              :
    """
    pychemia.pcm_log.debug('Tests (pychemia.core.structure)')
    a = 4.05
    b = a / 2
    fcc = pychemia.Structure(symbols=['Au'],
                             cell=[[0, b, b], [b, 0, b], [b, b, 0]],
                             periodicity=True)
    assert (fcc.natom == 1)
    fcc_copy = fcc.copy()
    fcc_copy.canonical_form()
    assert (abs(fcc.volume - fcc_copy.volume) < 1E-13)
    assert (np.linalg.norm(fcc_copy.lattice.angles - fcc.lattice.angles) <
            1E-10)
    spc = fcc.supercell((3, 3, 3))
    assert (spc.natom == 27)
Beispiel #11
0
def run_one(a):
    """
    Take one OQMD 'Entry' object, search all the calculations associated and take the best calculation
    in order to insert its data into the PyChemia Database

    :param a: OQMD Entry object
    :return:
    """

    energy = 1E10
    best_calculation = None

    if a.calculation_set.count() > 0:

        if 'standard' in a.calculations:
            best_calculation = a.calculations['standard']
            calculation_name = 'standard'
        elif 'fine_relax' in a.calculations:
            best_calculation = a.calculations['fine_relax']
            calculation_name = 'fine_relax'
        elif 'coarse_relax' in a.calculations:
            best_calculation = a.calculations['coarse_relax']
            calculation_name = 'coarse_relax'
        elif 'static' in a.calculations:
            best_calculation = a.calculations['static']
            calculation_name = 'static'
        elif 'relaxation' in a.calculations:
            best_calculation = a.calculations['relaxation']
            calculation_name = 'relaxation'
        elif len(a.calculations) > 0:
            calculations = sorted(a.calculations.keys())
            print('Calculations found: %s, using the last one' % calculations)
            best_calculation = a.calculations[calculations[-1]]
            calculation_name = calculations[-1]
        else:
            print('ERROR: Count > 0 and no calculation found')

    if best_calculation is not None:
        structure_name = None
        if best_calculation.output is not None:
            structure_used = best_calculation.output
            structure_id = best_calculation.output_id
            from_output = True
        elif best_calculation.input is not None:
            print(
                'WARNING: No data was found from the output of the calculation, using input geometries and leaving energetics empty'
            )
            structure_used = best_calculation.input
            structure_id = best_calculation.input_id
            from_output = False
    else:
        calculation_name = None
        if a.structures is not None and len(a.structures) > 0:
            struct_keys = sorted(a.structures.keys())
            print(
                "WARNING: Calculation not found for %s. Structures found: %s using the first one "
                % (a, struct_keys))
            structure_used = a.structures[struct_keys[0]]
            structure_id = None
            from_output = False
            structure_name = struct_keys[0]
        else:
            print("ERROR: No calculation and no structure found for %s" % a)
            return None, None

    cell = structure_used.cell.T
    symbols = atomic_symbol(structure_used.atomic_numbers)
    reduced = structure_used.coords

    structure = pychemia.Structure(cell=cell, symbols=symbols, reduced=reduced)
    entry_id = a.id

    if best_calculation is not None:
        calculation_id = best_calculation.id
        energy_pa = best_calculation.energy_pa
        energy = best_calculation.energy
        band_gap = best_calculation.band_gap
        settings = best_calculation.settings

        try:
            spacegroup_number = best_calculation.output.spacegroup.number
        except AttributeError:
            spacegroup_number = None

    else:
        calculation_id = None
        energy_pa = None
        energy = None
        band_gap = None
        settings = None
        spacegroup_number = None
        from_output = False

    try:
        symm = pychemia.crystal.CrystalSymmetry(structure)
        sym2 = symm.number(1E-2)
    except ValueError:
        sym2 = None

    properties = {
        'oqmd': {
            'structure_id': structure_id,
            'entry_id': entry_id,
            'calculation_id': calculation_id,
            'energy_pa': energy_pa,
            'energy': energy,
            'band_gap': band_gap,
            'settings': settings,
            'from_output': from_output,
            'calculation_name': calculation_name,
            'structure_name': structure_name,
            'spacegroup_number': spacegroup_number
        },
        'spacegroup_number': {
            'value': sym2,
            'symprec': 1E-2
        }
    }

    return structure, properties
Beispiel #12
0
def rotate_along_indices(structure, h, k, l, layers, tol=1.e-5):
    cell = structure.cell
    a1 = np.array(cell[0])
    a2 = np.array(cell[1])
    a3 = np.array(cell[2])
    rcell = structure.lattice.reciprocal().cell
    b1 = np.array(rcell[0])
    b2 = np.array(rcell[1])
    b3 = np.array(rcell[2])

    # Solve equation pk + ql = 1 for p and q using extended_Euclidean algorithm

    v = ext_gcd(k, l)
    p = v[0]
    q = v[1]
    # print('p = ', p)
    # print('q = ', q)

    k1 = np.dot(p * (k * a1 - h * a2) + q * (l * a1 - h * a3), l * a2 - k * a3)
    k2 = np.dot(l * (k * a1 - h * a2) - k * (l * a1 - h * a3), l * a2 - k * a3)
    # print("\n\nk1 = ", k1)
    # print("k2 = ", k2)

    if abs(k2) > tol:
        c = -int(round(k1 / k2))
        # print("c = -int(round(k1/k2)) = ", c)
        p, q = p + c * l, q - c * k

    # Calculate lattice vectors {v1, v2, v3} defining basis of the new cell

    v1 = p * (k * a1 - h * a2) + q * (l * a1 - h * a3)
    v2 = l * a2 - k * a3
    n = p * k + q * l
    v = ext_gcd(n, h)
    a = v[0]
    b = v[1]
    v3 = b * a1 + a * p * a2 + a * q * a3
    newbasis = np.array([v1, v2, v3])

    #    transformation = np.array([[p*k+q*l, -h*p, -h], [0, l, -k], [b, a*p, a*q]])
    #    inv_transformation = np.linalg.inv(transformation)

    symbols = []
    positions = structure.positions + np.tile(
        np.dot(structure.cell.T, np.array([0, 0, 0])).reshape(1, 3),
        (structure.natom, 1))
    reduced = np.linalg.solve(newbasis.T, positions.T).T
    for i in range(3):
        reduced[:, i] %= 1.0
    symbols += structure.symbols
    surf = pychemia.Structure(symbols=symbols, reduced=reduced, cell=newbasis)

    if layers > 1:
        new_surf = surf.supercell((1, 1, layers))
        cell = new_surf.cell
        # cell[2] = cell[2]+(layers+1)*cell[1]+(layers+1)*cell[0]
        surf = pychemia.Structure(symbols=new_surf.symbols,
                                  positions=new_surf.positions,
                                  cell=cell)

    #    print '\n\n********* Lattice vectors of the original cell *********\n\n', cell
    #    print '\n\n********* ATOMIC positions in the original cell **********\n', structure.positions
    #    print '\nTotal number of atoms in cell = ', structure.natom

    # Now create the surface starting from the original structure
    #    surf = structure.copy()
    #    surf.set_cell(newbasis)

    #    print '\n\n********* New basis of the surface cell *********\n\n', surf.cell
    #    print '\n\n********* Atomic coordinates in the newbasis of surface cell *********\n\n', surf.positions

    #    surf = surf.supercell((1, 1, layers))
    #    a1, a2, a3 = surf.cell

    #    surf.set_cell([a1, a2,
    #                   np.cross(a1, a2) * np.dot(a3, np.cross(a1, a2)) /
    #                   np.linalg.norm(np.cross(a1, a2)) ** 2])

    # Change unit cell to have the x-axis parallel with a surface vector
    # and z perpendicular to the surface:

    #    a1, a2, a3 = surf.cell
    #    surf.set_cell([(np.linalg.norm(a1), 0, 0),
    #                   (np.dot(a1, a2) / np.linalg.norm(a1),
    #                    np.sqrt(np.linalg.norm(a2) ** 2 - (np.dot(a1, a2) / np.linalg.norm(a1)) ** 2), 0),
    #                   (0, 0, np.linalg.norm(a3))])

    # Move atoms into the unit cell:

    #    scaled = surf.reduced
    #    scaled[:, :2] %= 1
    #    surf.set_reduced(scaled)
    #    surf.center(vacuum=vacuum, axis=2)
    return surf
Beispiel #13
0
    def worker(self, path):
        """
        From a given 'path', the worker will collect information from several files
        such as:

        fireball.in
        eigen.dat
        param.dat
        answer.bas
        output collected from the standard output of fireball.x


        After collecting data into dictionaries, the data is stored in a PyChemia database
        """

        pcdb = get_database(self.db_settings)
        files = os.listdir(path)
        properties = {}
        geo = None

        if os.path.lexists(path+os.sep+'fireball.in'):
            properties['path'] = path
            score = 'input'
            try:
                invars = pychemia.code.fireball.read_fireball_in(path + os.sep + 'fireball.in')
                properties['input'] = invars
            except:
                print('Bad fireball.in on %s' % path)

            if os.path.exists(path+os.sep+'param.dat'):
                try:
                    score += '+param'
                    param = pychemia.code.fireball.read_param(path + os.sep + 'param.dat')
                    properties['param_dat'] = param
                except:
                    print('Bad param.dat')

            if os.path.lexists(path+os.sep+'eigen.dat'):
                try:
                    score += '+eigen'
                    eigen = pychemia.code.fireball.read_eigen(path + os.sep + 'eigen.dat')
                    properties['eigen_dat'] = eigen
                except:
                    print('bad eigen.dat')

            if os.path.lexists(path+os.sep+'answer.bas'):
                try:
                    score += '+answer'
                    geo = pychemia.code.fireball.read_geometry_bas(path + os.sep + 'answer.bas')
                    periodic = False
                except:
                    print('Bad answer.bas')

            for ioutput in self.output_names:
                if os.path.isfile(path + os.sep + ioutput):
                    rf = open(path + os.sep + ioutput)
                    line = rf.readline()
                    rf.close()
                    if "Welcome to FIREBALL" in line:
                        try:
                            output = pychemia.code.fireball.read_final_fireball_relax(path + os.sep + ioutput)
                            properties['output'] = output
                            break
                        except:
                            print('Bad output %s on %s' % (ioutput, path))

            for ifile in files:
                if ifile[-3:] == 'lvs':
                    try:
                        cell = pychemia.code.fireball.read_lvs(path + os.sep + ifile)
                        periodic = True
                        lat = pychemia.crystral.Lattice(cell)
                        if lat.volume > 1E7:
                            print('Lattice too big, assuming non-periodic structure')
                            periodic = False
                    except:
                        print('Bad %s' % ifile)

        if geo is not None:
            print('DB: %d entries, Path: %s' % (pcdb.entries.count(), path))
            if periodic:
                st = pychemia.Structure(symbols=geo.symbols, positions=geo.positions, cell=cell)
            else:
                st = pychemia.Structure(symbols=geo.symbols, positions=geo.positions, periodicity=False)

            pcdb.insert(st, properties)
        return properties
Beispiel #14
0
def generator(args):
    elements = args['elements']
    composition = args['composition']
    spg = args['spg']
    wyckoff_position = args['wyckoff_position']
    generation_info = args['generation_information']
    cs = crystal.random_crystal(int(spg),
                                species=elements,
                                numIons=composition,
                                factor=1)
    if not cs.valid:
        return None

    if wyckoff_position in list(
            np.unique([
                '%d%s' % (s.wp.multiplicity, s.wp.letter)
                for s in cs.wyckoff_sites
            ])):
        cell = cs.struct.lattice.matrix
        reduced = cs.struct.frac_coords
        symbols = [ele.value for ele in cs.struct.species]
        structure = pychemia.Structure(cell=cell,
                                       symbols=symbols,
                                       reduced=reduced)
        sym = pychemia.crystal.CrystalSymmetry(structure)
        properties = {
            'pretty_formula':
            structure.get_composition().sorted_formula(sortby='electroneg'),
            'elements':
            elements,
            'generation_information':
            generation_info,
            'requested_spg':
            spg,
            'spacegroup': {
                'number':
                sym.number(symprec=1e-3),
                'symbol':
                sym.symbol(symprec=1e-3),
                'spglib_wyckoffs':
                sym.get_symmetry_dataset()['wyckoffs'],
                'wyckoffs':
                list(
                    np.unique([
                        '%d%s' % (s.wp.multiplicity, s.wp.letter)
                        for s in cs.wyckoff_sites
                    ])),
            }
        }

        print(
            str(properties['spacegroup']['number']) + '-' +
            str(structure.nspecies) + '-' + properties['pretty_formula'] +
            '.vasp')
        if spg != sym.number(symprec=1e-3):

            print('++++++++++++++++++++++++++++++++++++++++++++')
            print('++++++++++++++++++++++++++++++++++++++++++++')
            print(
                'The requested space group %d not equal to the generated space group %d'
                % (spg, sym.number(symprec=1e-3)))
            cs.print_all()
            print(cs.frac_coords.round(5))
            print(structure.reduced)
            print("--------------------------------------------")
            print('elements', elements)
            print('compisotion', composition)
            print('spg', spg)
            return None

        return (structure, properties)
Beispiel #15
0
def read_poscar(path='POSCAR'):
    """
    Load a POSCAR file and return a pychemia structure object

    :param path: (str) Filename of the POSCAR to read
    :return:
    """

    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:
        print("POSCAR path not found")
        return

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

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

    line = rf.readline()
    species = None

    try:
        natom_per_species = _np.array([int(x) for x in line.split()])
        # print 'Old Format'
    except ValueError:
        # print 'New format'
        species = [x for x in line.split()]
        line = rf.readline()
        natom_per_species = _np.array([int(x) for x in line.split()])

    natom = _np.sum(natom_per_species)

    if species is None:
        if os.path.isfile(potcarfile):
            species = get_species(potcarfile)
        elif len(comment.split()) == len(natom_per_species):
            species = comment.split()
        else:
            print(""" ERROR: The POSCAR does not contain information about the species present on the structure
            You can set a consistent POTCAR along the POSCAR or
            modify your POSCAR by adding the atomic symbol on the sixth line of the file""")
            return None

    if not species:
        print('No information about species')
        raise ValueError()

    symbols = []
    for i in range(len(natom_per_species)):
        numspe = natom_per_species[i]
        for j in range(numspe):
            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 = _np.array(pos).reshape((-1, 3))

    if kmode == 'Cartesian':
        return pychemia.Structure(cell=newcell, symbols=symbols, reduced=pos, comment=comment)
    else:
        return pychemia.Structure(cell=newcell, symbols=symbols, reduced=pos, comment=comment)
Beispiel #16
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 = pychemia.Structure(positions=new_positions,
                                           symbols=symbols,
                                           periodicity=False)
        lj = pychemia.code.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 = pychemia.Structure(positions=pos_orig,
                            symbols=symbols,
                            periodicity=False)
    lj = pychemia.code.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 = pychemia.Structure(positions=pos_dest,
                            symbols=symbols,
                            periodicity=False)
    lj = pychemia.code.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)
Beispiel #17
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)