Пример #1
0
def get_force_constants_from_phonopy(structure, ph_settings, force_sets):
    """
    Calculate the force constants locally using phonopy

    :param structure:
    :param phonopy_input: ParameterData object that contains phonopy settings
    :param force_sets: ForceSetsData object that contains the atomic forces and displacements info (datasets dict in phonopy)
    :return: ForceConstantsData object containing the 2nd order force constants calculated with phonopy
    """
    from phonopy import Phonopy

    # Generate phonopy phonon object

    phonon = Phonopy(phonopy_bulk_from_structure(structure),
                     ph_settings.dict.supercell,
                     primitive_matrix=ph_settings.dict.primitive,
                     symprec=ph_settings.dict.symmetry_precision)

    phonon.generate_displacements(distance=ph_settings.dict.distance)

    # Build data_sets from forces of supercells with displacments
    phonon.set_displacement_dataset(force_sets.get_force_sets())
    phonon.produce_force_constants()

    force_constants = ForceConstantsData(data=phonon.get_force_constants())

    return {'force_constants': force_constants}
Пример #2
0
def get_force_sets_inline(**kwargs):
    from phonopy.structure.atoms import Atoms as PhonopyAtoms
    from phonopy import Phonopy

    structure = kwargs.pop('structure')
    phonopy_input = kwargs.pop('phonopy_input').get_dict()

    # Generate phonopy phonon object
    bulk = PhonopyAtoms(symbols=[site.kind_name for site in structure.sites],
                        positions=[site.position for site in structure.sites],
                        cell=structure.cell)

    phonon = Phonopy(bulk,
                     phonopy_input['supercell'],
                     primitive_matrix=phonopy_input['primitive'],
                     symprec=phonopy_input['symmetry_precision'])

    phonon.generate_displacements(distance=phonopy_input['distance'])

    # Build data_sets from forces of supercells with displacments
    data_sets = phonon.get_displacement_dataset()
    for i, first_atoms in enumerate(data_sets['first_atoms']):
        first_atoms['forces'] = kwargs.pop(
            'force_{}'.format(i)).get_array('forces')[-1]

    data = ArrayData()
    data.set_array('force_sets', np.array(data_sets))

    return {'phonopy_output': data}
Пример #3
0
def get_phonon_configs(calc, at, disps, scell, config_type):

    cell = PhonopyAtoms(symbols=at.get_chemical_symbols(),
                        cell=at.get_cell(),
                        positions=at.get_positions())

    phonon = Phonopy(cell, np.eye(3) * scell)

    al = []

    for disp in disps:
        print(disp, config_type)
        phonon.generate_displacements(distance=disp)
        supercells = phonon.get_supercells_with_displacements()

        for (i, scell) in enumerate(supercells):
            at = ase.Atoms(symbols=scell.get_chemical_symbols(),
                           scaled_positions=scell.get_scaled_positions(),
                           cell=scell.get_cell(),
                           pbc=True)

            at.set_calculator(calc)
            e = at.get_potential_energy()
            f = at.get_forces()
            v = -1.0 * at.get_volume() * at.get_stress(voigt=False)
            at.arrays["force"] = f
            at.info["virial"] = v
            at.info["config_type"] = "PH_" + config_type
            at.info["energy_TB"] = e
            #write("PH_{}_{}_scell_{}.xyz".format(config_type, i, disp), at)
            al.append(at)

    return al
Пример #4
0
def create_supercells_with_displacements_inline(**kwargs):
    from phonopy.structure.atoms import Atoms as PhonopyAtoms
    from phonopy import Phonopy

    structure = kwargs.pop('structure')
    phonopy_input = kwargs.pop('phonopy_input').get_dict()

    # Generate phonopy phonon object
    bulk = PhonopyAtoms(symbols=[site.kind_name for site in structure.sites],
                        positions=[site.position for site in structure.sites],
                        cell=structure.cell)

    phonon = Phonopy(bulk,
                     phonopy_input['supercell'],
                     primitive_matrix=phonopy_input['primitive'],
                     symprec=phonopy_input['symmetry_precision'])

    phonon.generate_displacements(distance=phonopy_input['distance'])

    cells_with_disp = phonon.get_supercells_with_displacements()

    # Transform cells to StructureData and set them ready to return
    disp_cells = {}

    for i, phonopy_supercell in enumerate(cells_with_disp):
        supercell = StructureData(cell=phonopy_supercell.get_cell())
        for symbol, position in zip(phonopy_supercell.get_chemical_symbols(),
                                    phonopy_supercell.get_positions()):
            supercell.append_atom(position=position, symbols=symbol)
        disp_cells["structure_{}".format(i)] = supercell

    return disp_cells
Пример #5
0
def phonons(model, bulk, supercell, dx, mesh=None, points=None, n_points=50):

    import model

    unitcell = PhonopyAtoms(symbols=bulk.get_chemical_symbols(),
                            cell=bulk.get_cell(),
                            scaled_positions=bulk.get_scaled_positions())
    phonon = Phonopy(unitcell, supercell)
    phonon.generate_displacements(distance=dx)

    sets_of_forces = []

    for s in phonon.get_supercells_with_displacements():
        at = Atoms(cell=s.get_cell(),
                   symbols=s.get_chemical_symbols(),
                   scaled_positions=s.get_scaled_positions(),
                   pbc=3 * [True])
        at.set_calculator(model.calculator)
        sets_of_forces.append(at.get_forces())

    phonon.set_forces(sets_of_forces=sets_of_forces)
    phonon.produce_force_constants()

    properties = {}

    if mesh is not None:
        phonon.set_mesh(mesh, is_gamma_center=True)
        qpoints, weights, frequencies, eigvecs = phonon.get_mesh()

        properties["frequencies"] = frequencies.tolist()
        properties["weights"] = weights.tolist()

    if points is not None:
        bands = []
        for i in range(len(points) - 1):
            band = []
            for r in np.linspace(0, 1, n_points):
                band.append(points[i] + (points[i + 1] - points[i]) * r)
            bands.append(band)

        phonon.set_band_structure(bands,
                                  is_eigenvectors=True,
                                  is_band_connection=False)
        band_q_points, band_distances, band_frequencies, band_eigvecs = phonon.get_band_structure(
        )

        band_distance_max = np.max(band_distances)
        band_distances = [(_b / band_distance_max).tolist()
                          for _b in band_distances]

        band_frequencies = [_b.tolist() for _b in band_frequencies]

        properties["band_q_points"] = band_q_points
        properties["band_distances"] = band_distances
        properties["band_frequencies"] = band_frequencies
        properties["band_eigvecs"] = band_eigvecs

    properties["phonopy"] = phonon

    return properties
Пример #6
0
def create_supercells_with_displacements_using_phonopy(structure, ph_settings):
    """
    Use phonopy to create the supercells with displacements to calculate the force constants by using
    finite displacements methodology

    :param structure: StructureData object
    :param phonopy_input: ParametersData object containing a dictionary with the data needed for phonopy
    :return: A set of StructureData Objects containing the supercells with displacements
    """
    from phonopy import Phonopy

    # Generate phonopy phonon object
    phonon = Phonopy(phonopy_bulk_from_structure(structure),
                     supercell_matrix=ph_settings.dict.supercell,
                     primitive_matrix=ph_settings.dict.primitive,
                     symprec=ph_settings.dict.symmetry_precision)

    phonon.generate_displacements(distance=ph_settings.dict.distance)

    cells_with_disp = phonon.get_supercells_with_displacements()

    # Transform cells to StructureData and set them ready to return
    data_sets = phonon.get_displacement_dataset()
    data_sets_object = ForceSetsData(data_sets=data_sets)

    disp_cells = {'data_sets': data_sets_object}
    for i, phonopy_supercell in enumerate(cells_with_disp):
        supercell = StructureData(cell=phonopy_supercell.get_cell())
        for symbol, position in zip(phonopy_supercell.get_chemical_symbols(),
                                    phonopy_supercell.get_positions()):
            supercell.append_atom(position=position, symbols=symbol)
        disp_cells["structure_{}".format(i)] = supercell

    return disp_cells
Пример #7
0
def get_displaced_structures(pmg_structure,
                             atom_disp=0.01,
                             supercell_matrix=None,
                             yaml_fname=None,
                             **kwargs):
    r"""
    Generate a set of symmetrically inequivalent displaced structures for
    phonon calculations.

    Args:
        pmg_structure (Structure): A pymatgen structure object.
        atom_disp (float): Atomic displacement. Default is 0.01 $\\AA$.
        supercell_matrix (3x3 array): Scaling matrix for supercell.
        yaml_fname (string): If not None, it represents the full path to
            the outputting displacement yaml file, e.g. disp.yaml.
        **kwargs: Parameters used in Phonopy.generate_displacement method.

    Return:
        A list of symmetrically inequivalent structures with displacements, in
        which the first element is the perfect supercell structure.
    """

    is_plusminus = kwargs.get("is_plusminus", "auto")
    is_diagonal = kwargs.get("is_diagonal", True)
    is_trigonal = kwargs.get("is_trigonal", False)

    ph_structure = get_phonopy_structure(pmg_structure)

    if supercell_matrix is None:
        supercell_matrix = np.eye(3) * np.array((1, 1, 1))

    phonon = Phonopy(unitcell=ph_structure, supercell_matrix=supercell_matrix)
    phonon.generate_displacements(
        distance=atom_disp,
        is_plusminus=is_plusminus,
        is_diagonal=is_diagonal,
        is_trigonal=is_trigonal,
    )

    if yaml_fname is not None:
        displacements = phonon.get_displacements()
        write_disp_yaml(
            displacements=displacements,
            supercell=phonon.get_supercell(),
            filename=yaml_fname,
        )

    # Supercell structures with displacement
    disp_supercells = phonon.get_supercells_with_displacements()
    # Perfect supercell structure
    init_supercell = phonon.get_supercell()
    # Structure list to be returned
    structure_list = [get_pmg_structure(init_supercell)]

    for c in disp_supercells:
        if c is not None:
            structure_list.append(get_pmg_structure(c))

    return structure_list
Пример #8
0
def test_nacl(ph_nacl: Phonopy):
    """Test displacements of NaCl 2x2x2."""
    dataset = deepcopy(ph_nacl.dataset)
    disp_ref = [[0, 0.01, 0.0, 0.0], [32, 0.01, 0.0, 0.0]]
    np.testing.assert_allclose(ph_nacl.displacements, disp_ref, atol=1e-8)
    ph_nacl.generate_displacements()
    np.testing.assert_allclose(ph_nacl.displacements, disp_ref, atol=1e-8)
    ph_nacl.dataset = dataset
Пример #9
0
def test_si(ph_si: Phonopy):
    """Test displacements of Si."""
    dataset = deepcopy(ph_si.dataset)
    disp_ref = [[0, 0.0, 0.0070710678118655, 0.0070710678118655]]
    np.testing.assert_allclose(ph_si.displacements, disp_ref, atol=1e-8)
    ph_si.generate_displacements()
    np.testing.assert_allclose(ph_si.displacements, disp_ref, atol=1e-8)
    ph_si.dataset = dataset
Пример #10
0
def phonopy_pre_process(cell, config_type, supercell_matrix=None):

    smat = [[3, 0, 0], [0, 3, 0], [0, 0, 3]]

    phonon = Phonopy(cell, smat)

    phonon.generate_displacements(distance=0.16)  #0.02
    print("[Phonopy] Atomic displacements:")
    disps = phonon.get_displacements()
    for d in disps:
        print("[Phonopy] %d %s" % (d[0], d[1:]))
    return phonon
Пример #11
0
def get_displaced_structures(pmg_structure, atom_disp=0.01,
                             supercell_matrix=None, yaml_fname=None, **kwargs):
    """
    Generate a set of symmetrically inequivalent displaced structures for
    phonon calculations.

    Args:
        pmg_structure (Structure): A pymatgen structure object.
        atom_disp (float): Atomic displacement. Default is 0.01 $\\AA$.
        supercell_matrix (3x3 array): Scaling matrix for supercell.
        yaml_fname (string): If not None, it represents the full path to
            the outputting displacement yaml file, e.g. disp.yaml.
        **kwargs: Parameters used in Phonopy.generate_displacement method.

    Return:
        A list of symmetrically inequivalent structures with displacements, in
        which the first element is the perfect supercell structure.
    """

    is_plusminus = kwargs.get("is_plusminus", "auto")
    is_diagonal = kwargs.get("is_diagonal", True)
    is_trigonal = kwargs.get("is_trigonal", False)

    ph_structure = get_phonopy_structure(pmg_structure)

    if supercell_matrix is None:
        supercell_matrix = np.eye(3) * np.array((1, 1, 1))

    phonon = Phonopy(unitcell=ph_structure, supercell_matrix=supercell_matrix)
    phonon.generate_displacements(distance=atom_disp,
                                  is_plusminus=is_plusminus,
                                  is_diagonal=is_diagonal,
                                  is_trigonal=is_trigonal)

    if yaml_fname is not None:
        displacements = phonon.get_displacements()
        directions = phonon.get_displacement_directions()
        write_disp_yaml(displacements=displacements,
                        supercell=phonon.get_supercell(),
                        directions=directions, filename=yaml_fname)

    # Supercell structures with displacement
    disp_supercells = phonon.get_supercells_with_displacements()
    # Perfect supercell structure
    init_supercell = phonon.get_supercell()
    # Structure list to be returned
    structure_list = [get_pmg_structure(init_supercell)]

    for c in disp_supercells:
        if c is not None:
            structure_list.append(get_pmg_structure(c))

    return structure_list
Пример #12
0
def _calc_quick(atoms, supercell=(1, 1, 1), delta=0.01):
    """Calculates the Hessian for a given atoms object just like :func:`calc`,
    *but*, it uses symmetry to speed up the calculation. Depending on the
    calculator being used, it is possible that the symmetrized result may be
    different from the full result with all displacements, done manually by
    :func:`calc`.

    Args:
        atoms (matdb.atoms.Atoms): atomic structure of the *primitive*.
        supercell (list): or `tuple` or :class:`numpy.ndarray` specifying the
          integer supercell matrix.
        delta (float): displacement in Angstroms of each atom when computing the
          phonons. 

    Returns:
        numpy.ndarray: Hessian matrix that has dimension `(natoms*3, natoms*3)`,
        where `natoms` is the number of atoms in the *supercell*.
    """
    #We need to make sure we are at the zero of the potential before
    ratoms = atoms.copy()
    try:
        with open("phonons.log", 'w') as f:
            with redirect_stdout(f):
                print(ratoms.get_forces())
                minim = FIRE(ratoms)
                minim.run(fmax=1e-4, steps=100)
    except:
        #The potential is unstable probably. Issue a warning.
        msg.warn(
            "Couldn't optimize the atoms object. Potential may be unstable.")

    primitive = matdb_to_phonopy(ratoms)
    phonon = Phonopy(primitive, conform_supercell(supercell))
    phonon.generate_displacements(distance=delta)
    supercells = phonon.get_supercells_with_displacements()
    pot = atoms.get_calculator()
    assert pot is not None

    forces = []
    for scell in supercells:
        matoms = phonopy_to_matdb(scell)
        #Call a manual reset of the calculator so that we explicitly recalculate
        #the forces for the current atoms object.
        pot.reset()
        matoms.set_calculator(pot)
        forces.append(matoms.get_forces())

    phonon.set_forces(forces)
    phonon.produce_force_constants()
    return unroll_fc(phonon._force_constants)
Пример #13
0
 def build_phonon(self, atoms = None, 
                    supercell_matrix = None, 
                    primitive_matrix = None,
                    distance = None):
     if atoms is None:
         atoms = self.atoms
     phonon = Phonopy(atoms,
                     supercell_matrix,
                     primitive_matrix = primitive_matrix)
     phonon.generate_displacements(distance = distance)
     self.log("[Phonopy] Atomic displacements:")
     disps = phonon.get_displacements()
     for d in disps:
         self.log("[Phonopy] %d %s" % (d[0], d[1:]))
     self.phonon = phonon
Пример #14
0
def phonopy_pre_process(cell, disp, config_type, supercell_matrix=None):

    if config_type == "al":
        print config_type
        smat = [[2, 0, 0], [0, 2, 0], [0, 0, 2]]
    else:
        smat = [[3, 0, 0], [0, 3, 0], [0, 0, 3]]

    phonon = Phonopy(cell, smat)

    phonon.generate_displacements(distance=disp)
    print("[Phonopy] Atomic displacements:")
    disps = phonon.get_displacements()
    for d in disps:
        print("[Phonopy] %d %s" % (d[0], d[1:]))
    return phonon
Пример #15
0
def test_tipn3(ph_tipn3: Phonopy):
    """Test displacements of Zr3N4."""
    dataset = deepcopy(ph_tipn3.dataset)
    disp_ref = [
        [0, 0.01, 0.0, 0.0],
        [0, 0.0, 0.01, 0.0],
        [0, 0.0, 0.0, 0.01],
        [0, 0.0, 0.0, -0.01],
        [16, 0.01, 0.0, 0.0],
        [16, 0.0, 0.01, 0.0],
        [16, 0.0, 0.0, 0.01],
        [16, 0.0, 0.0, -0.01],
        [32, 0.01, 0.0, 0.0],
        [32, 0.0, 0.01, 0.0],
        [32, 0.0, -0.01, 0.0],
        [32, 0.0, 0.0, 0.01],
        [32, 0.0, 0.0, -0.01],
        [40, 0.01, 0.0, 0.0],
        [40, 0.0, 0.01, 0.0],
        [40, 0.0, 0.0, 0.01],
        [40, 0.0, 0.0, -0.01],
    ]
    np.testing.assert_allclose(ph_tipn3.displacements, disp_ref, atol=1e-8)
    ph_tipn3.generate_displacements()
    disp_gen = [
        [0, 0.006370194270018462, 0.006021020526083804, 0.00481330829956917],
        [
            0, -0.006370194270018462, -0.006021020526083804,
            -0.00481330829956917
        ],
        [16, 0.006370194270018462, 0.006021020526083804, 0.00481330829956917],
        [
            16, -0.006370194270018462, -0.006021020526083804,
            -0.00481330829956917
        ],
        [32, 0.007267439570389398, 0.0068690845162028965, 0.0],
        [32, -0.007267439570389398, -0.0068690845162028965, 0.0],
        [32, 0.0, 0.0, 0.01],
        [32, 0.0, 0.0, -0.01],
        [40, 0.006370194270018462, 0.006021020526083804, 0.00481330829956917],
        [
            40, -0.006370194270018462, -0.006021020526083804,
            -0.00481330829956917
        ],
    ]
    np.testing.assert_allclose(ph_tipn3.displacements, disp_gen, atol=1e-8)
    ph_tipn3.dataset = dataset
Пример #16
0
def create_supercells_with_displacements_using_phonopy(structure,
                                                       phonopy_input):
    """
    Create the supercells with the displacements to use the finite displacements methodology to calculate the
    force constants
    :param structure: Aiida StructureData Object
    :param phonopy_input: Aiida Parametersdata object containing a dictionary with the data needed to run phonopy:
            supercells matrix, primitive matrix and displacement distance.
    :return: dictionary of Aiida StructureData Objects containing the cells with displacements
    """
    from phonopy.structure.atoms import Atoms as PhonopyAtoms
    from phonopy import Phonopy
    import numpy as np

    # Generate phonopy phonon object
    bulk = PhonopyAtoms(symbols=[site.kind_name for site in structure.sites],
                        positions=[site.position for site in structure.sites],
                        cell=structure.cell)

    phonopy_input = phonopy_input.get_dict()
    phonon = Phonopy(bulk,
                     phonopy_input['supercell'],
                     primitive_matrix=phonopy_input['primitive'])

    phonon.generate_displacements(distance=phonopy_input['distance'])

    cells_with_disp = phonon.get_supercells_with_displacements()

    # Transform cells to StructureData and set them ready to return
    data_sets = phonon.get_displacement_dataset()
    data_sets_object = ArrayData()
    for i, first_atoms in enumerate(data_sets['first_atoms']):
        data_sets_array = np.array([
            first_atoms['direction'], first_atoms['number'],
            first_atoms['displacement']
        ])
        data_sets_object.set_array('data_sets_{}'.format(i), data_sets_array)

    disp_cells = {'data_sets': data_sets_object}
    for i, phonopy_supercell in enumerate(cells_with_disp):
        supercell = StructureData(cell=phonopy_supercell.get_cell())
        for symbol, position in zip(phonopy_supercell.get_chemical_symbols(),
                                    phonopy_supercell.get_positions()):
            supercell.append_atom(position=position, symbols=symbol)
        disp_cells["structure_{}".format(i)] = supercell

    return disp_cells
Пример #17
0
def phonopy_pre_process(cell, supercell_matrix=None):

    if supercell_matrix is None:
        smat = [[2,0,0], [0,2,0], [0,0,2]],
    else:
        smat = supercell_matrix
    phonon = Phonopy(cell,
                     smat,
                     primitive_matrix=[[0, 0.5, 0.5],
                                       [0.5, 0, 0.5],
                                       [0.5, 0.5, 0]])
    phonon.generate_displacements(distance=0.03)
    print("[Phonopy] Atomic displacements:")
    disps = phonon.get_displacements()
    for d in disps:
        print("[Phonopy] %d %s" % (d[0], d[1:]))
    return phonon
Пример #18
0
def get_force_constants_from_phonopy(**kwargs):
    """
    Calculate the force constants using phonopy
    :param kwargs:
    :return:
    """

    from phonopy.structure.atoms import Atoms as PhonopyAtoms
    from phonopy import Phonopy
    import numpy as np
    # print 'function',kwargs

    structure = kwargs.pop('structure')
    phonopy_input = kwargs.pop('phonopy_input').get_dict()

    # Generate phonopy phonon object
    bulk = PhonopyAtoms(symbols=[site.kind_name for site in structure.sites],
                        positions=[site.position for site in structure.sites],
                        cell=structure.cell)

    phonon = Phonopy(bulk,
                     phonopy_input['supercell'],
                     primitive_matrix=phonopy_input['primitive'],
                     distance=phonopy_input['distance'])

    phonon.generate_displacements(distance=phonopy_input['distance'])

    # Build data_sets from forces of supercells with displacments

    data_sets = phonon.get_displacement_dataset()
    for i, first_atoms in enumerate(data_sets['first_atoms']):
        forces = kwargs.pop('forces_{}'.format(i)).get_array('forces')[0]
        first_atoms['forces'] = np.array(forces, dtype='double', order='c')

    # LOCAL calculation

    # Calculate and get force constants
    phonon.set_displacement_dataset(data_sets)
    phonon.produce_force_constants()

    force_constants = phonon.get_force_constants()

    array_data = ArrayData()
    array_data.set_array('force_constants', force_constants)

    return {'array_data': array_data}
Пример #19
0
    def _get_phononobject_phonopy(self,
                                  structure,
                                  potential,
                                  smat,
                                  save_parameters,
                                  path,
                                  displacement_distance=0.01):
        cell = get_phonopy_structure(structure)
        phonon = Phonopy(cell,
                         smat,
                         primitive_matrix=[[1.0, 0.0, 0.0], [0.0, 1, 0.0],
                                           [0., 0., 1.0]],
                         factor=VaspToTHz)

        # displacements
        phonon.generate_displacements(distance=displacement_distance)
        print("[Phonopy] Atomic displacements:")
        disps = phonon.get_displacements()
        for d in disps:
            print("[Phonopy] %d %s" % (d[0], d[1:]))

        supercells = phonon.get_supercells_with_displacements()
        # Force calculations by calculator
        set_of_forces = []
        for scell in supercells:
            cell = Atoms(symbols=scell.get_chemical_symbols(),
                         scaled_positions=scell.get_scaled_positions(),
                         cell=scell.get_cell(),
                         pbc=True)
            cell.set_calculator(potential)
            # this part is adapted from: https://web.archive.org/web/20200610084959/https://github.com/phonopy/phonopy/blob/develop/example/ase/8Si-phonon.py
            # Copyright by Atsushi Togo
            forces = cell.get_forces()
            drift_force = forces.sum(axis=0)
            print(
                ("[Phonopy] Drift force:" + "%11.5f" * 3) % tuple(drift_force))
            for force in forces:
                force -= drift_force / forces.shape[0]
            set_of_forces.append(forces)

        phonon.produce_force_constants(forces=set_of_forces)
        if save_parameters:
            phonon.save(path)
        return phonon
Пример #20
0
def test_zr3n4(ph_zr3n4: Phonopy):
    """Test displacements of Zr3N4."""
    dataset = deepcopy(ph_zr3n4.dataset)
    disp_ref = [
        [0, 0.01, 0.0, 0.0],
        [0, -0.01, 0.0, 0.0],
        [16, 0.01, 0.0, 0.0],
        [16, 0.0, 0.01, 0.0],
    ]
    np.testing.assert_allclose(ph_zr3n4.displacements, disp_ref, atol=1e-8)
    ph_zr3n4.generate_displacements()
    disp_gen = [
        [0, 0.01, 0.0, 0.0],
        [0, -0.01, 0.0, 0.0],
        [16, 0.007071067811865475, 0.007071067811865475, 0.0],
        [16, -0.007071067811865475, -0.007071067811865475, 0.0],
    ]
    np.testing.assert_allclose(ph_zr3n4.displacements, disp_gen, atol=1e-8)
    ph_zr3n4.dataset = dataset
Пример #21
0
def test_sno2(ph_sno2: Phonopy):
    """Test displacements of SnO2."""
    dataset = deepcopy(ph_sno2.dataset)
    disp_ref = [
        [0, 0.01, 0.0, 0.0],
        [0, -0.01, 0.0, 0.0],
        [0, 0.0, 0.0, 0.01],
        [48, 0.01, 0.0, 0.0],
        [48, 0.0, 0.0, 0.01],
    ]
    np.testing.assert_allclose(ph_sno2.displacements, disp_ref, atol=1e-8)
    ph_sno2.generate_displacements()
    disp_gen = [
        [0, 0.007032660602415084, 0.0, 0.007109267532681459],
        [0, -0.007032660602415084, 0.0, -0.007109267532681459],
        [48, 0.007032660602415084, 0.0, 0.007109267532681459],
    ]
    np.testing.assert_allclose(ph_sno2.displacements, disp_gen, atol=1e-8)
    ph_sno2.dataset = dataset
Пример #22
0
def get_initialized_phononopy_instance(initial_structure,
                                       phonopy_inputs,
                                       force_constants_path=None,
                                       born_path=None):
    """
	Initializes and returns a valid Phonopy instance and with displacements internally generated.

	If force_constants_path is specified, the phonopy instance is initialized with the force constants at the given path.
	If the born_path is specified, the born file at this path is used to initialize the nac parameters of the phonopy instance, but
	only if the nac key has a value of true in the phonopy_inputs dictionary.

	phonopy_inputs should be a dictionary that looks like:

	phonopy_inputs_dictionary = {
		'supercell_dimensions': [2, 2, 2],
		'symprec': 0.001,
		'displacement_distance': 0.01,
		'nac': True
		...
	}
	"""

    unit_cell_phonopy_structure = convert_structure_to_phonopy_atoms(
        initial_structure)
    supercell_dimensions_matrix = np.diag(
        phonopy_inputs['supercell_dimensions'])

    phonon = Phonopy(unitcell=unit_cell_phonopy_structure,
                     supercell_matrix=supercell_dimensions_matrix,
                     symprec=phonopy_inputs['symprec'])
    phonon.generate_displacements(
        distance=phonopy_inputs['displacement_distance'])

    if force_constants_path != None:
        force_constants = parse_FORCE_CONSTANTS(filename=force_constants_path)
        phonon.set_force_constants(force_constants)

    if born_path != None and (phonopy_inputs.has_key('nac')
                              and phonopy_inputs['nac']):
        nac_params = parse_BORN(phonon.get_primitive(), filename=born_path)
        phonon.set_nac_params(nac_params)

    return phonon
Пример #23
0
def get_phonon_configs(calc, at, disps, scell, config_type):

    cell = PhonopyAtoms(symbols=at.get_chemical_symbols(),
                        cell=at.get_cell(),
                        positions=at.get_positions())

    phonon = Phonopy(cell, np.eye(3) * scell)

    al = []

    for disp in disps:
        phonon.generate_displacements(distance=disp)
        supercells = phonon.get_supercells_with_displacements()

        for (i, scell) in enumerate(supercells):
            at = Atoms(symbols=scell.get_chemical_symbols(),
                       scaled_positions=scell.get_scaled_positions(),
                       cell=scell.get_cell(),
                       pbc=True)

            at.set_calculator(calc)

            energy = at.get_potential_energy(force_consistent=True)
            forces = at.get_forces()
            stress = at.get_stress(voigt=False)

            drift_force = forces.sum(axis=0)
            print(("[Phonopy] Drift force:" + "%11.5f" * 3) %
                  tuple(drift_force))
            # Simple translational invariance
            for force in forces:
                force -= drift_force / forces.shape[0]
            at.arrays["force"] = forces
            at.info["virial"] = -1.0 * at.get_volume() * stress
            at.info["energy"] = energy
            at.info["config_type"] = "PH_" + config_type
            write("PH_{}_{}_scell_{}.xyz".format(config_type, i, disp), at)
            al.append(at)

    return al
Пример #24
0
    def runSimulation(self):
        starting_struct = singleFromFile(self.args)
        relaxed_struct = runCalc("all_relax", ["structures"],
                                 [starting_struct], self.args)["structures"][0]

        phonopy_struct = get_phonopy_structure(relaxed_struct)

        supercell_matrix = 3 * eye(3)
        phonon = Phonopy(phonopy_struct, supercell_matrix)
        phonon.generate_displacements(distance=0.01)
        supercells = phonon.supercells_with_displacements
        phonon_structs = [get_pmg_structure(struct) for struct in supercells]

        forces = runCalc("all_static", ["forces"], phonon_structs,
                         self.args)["forces"]

        phonon.set_forces(array(forces))
        phonon.produce_force_constants()
        phonon.symmetrize_force_constants()

        self.plotter = PhononBSPlotter(
            get_phonon_band_structure_symm_line_from_fc(
                relaxed_struct, supercell_matrix, phonon.force_constants))
Пример #25
0
def test_tio2(ph_tio2: Phonopy):
    """Test displacements of TiO2."""
    dataset = deepcopy(ph_tio2.dataset)
    disp_ref = [
        [0, 0.01, 0.0, 0.0],
        [0, 0.0, 0.01, 0.0],
        [0, 0.0, 0.0, 0.01],
        [0, 0.0, 0.0, -0.01],
        [72, 0.01, 0.0, 0.0],
        [72, 0.0, 0.0, 0.01],
    ]
    np.testing.assert_allclose(ph_tio2.displacements, disp_ref, atol=1e-8)
    ph_tio2.generate_displacements()
    disp_gen = [
        [0, 0.0060687317141537135, 0.0060687317141537135, 0.0051323474905008],
        [
            0, -0.0060687317141537135, -0.0060687317141537135,
            -0.0051323474905008
        ],
        [72, 0.007635558297727332, 0.0, 0.006457418174627326],
        [72, -0.007635558297727332, 0.0, -0.006457418174627326],
    ]
    np.testing.assert_allclose(ph_tio2.displacements, disp_gen, atol=1e-8)
    ph_tio2.dataset = dataset
Пример #26
0
def calculate_phonon(atoms,
                     calc,
                     ndim=np.eye(3),
                     primitive_matrix=np.eye(3),
                     distance=0.01,
                     factor=VaspToTHz,
                     is_symmetry=True,
                     symprec=1e-5,
                     func=None,
                     **func_args):
    """
    """
    if 'magmoms' in atoms.arrays:
        is_mag = True
    else:
        is_mag = False
    # 1. get displacements and supercells
    atoms.set_calculator(calc)
    # bulk = PhonopyAtoms(atoms=atoms)
    if is_mag:
        bulk = PhonopyAtoms(
            symbols=atoms.get_chemical_symbols(),
            scaled_positions=atoms.get_scaled_positions(),
            cell=atoms.get_cell(),
            magmoms=atoms.arrays['magmoms'],
        )
    else:
        bulk = PhonopyAtoms(symbols=atoms.get_chemical_symbols(),
                            scaled_positions=atoms.get_scaled_positions(),
                            cell=atoms.get_cell())

    phonon = Phonopy(bulk,
                     ndim,
                     primitive_matrix=primitive_matrix,
                     factor=factor,
                     symprec=symprec)
    phonon.generate_displacements(distance=distance)
    disps = phonon.get_displacements()
    for d in disps:
        print("[phonopy] %d %s" % (d[0], d[1:]))
    supercell0 = phonon.get_supercell()
    supercells = phonon.get_supercells_with_displacements()
    write_supercells_with_displacements(supercell0, supercells)
    write_disp_yaml(disps, supercell0)

    # 2. calculated forces.
    set_of_forces = []
    for iscell, scell in enumerate(supercells):
        cell = Atoms(symbols=scell.get_chemical_symbols(),
                     scaled_positions=scell.get_scaled_positions(),
                     cell=scell.get_cell(),
                     pbc=True)
        if is_mag:
            cell.set_initial_magnetic_moments(
                atoms.get_initial_magnetic_moments())
        cell.set_calculator(calc)
        dir_name = "PHON_CELL%s" % iscell
        cur_dir = os.getcwd()
        if not os.path.exists(dir_name):
            os.mkdir(dir_name)
        os.chdir(dir_name)
        forces = cell.get_forces()
        #print "[Phonopy] Forces: %s" % forces
        # Do something other than calculating the forces with func.
        # func: func(atoms, calc, func_args)
        if func is not None:
            func(cell, calc, **func_args)
        os.chdir(cur_dir)
        drift_force = forces.sum(axis=0)
        #print "[Phonopy] Drift force:", "%11.5f" * 3 % tuple(drift_force)
        # Simple translational invariance
        for force in forces:
            force -= drift_force / forces.shape[0]
        set_of_forces.append(forces)

    # Phonopy post-process
    phonon.produce_force_constants(forces=set_of_forces)
    force_constants = phonon.get_force_constants()
    write_FORCE_CONSTANTS(force_constants, filename='FORCE_CONSTANTS')
    print('')
    print("[Phonopy] Phonon frequencies at Gamma:")
    for i, freq in enumerate(phonon.get_frequencies((0, 0, 0))):
        print("[Phonopy] %3d: %10.5f THz" % (i + 1, freq))  # THz
        print("[Phonopy] %3d: %10.5f cm-1" % (i + 1, freq * 33.35))  #cm-1
    return phonon
Пример #27
0
def onGrid(
    qpoints,
    supercell_matrix,
    force_constants,
    freq2omega=THz2meV,
    poscar='POSCAR',
):
    """use phonopy to compute phonon frequencies and polarizations
    for the given Q points on a grid

    force_constants: instance
    """

    # set up Si crystal lattice
    bulk = vasp.read_vasp(poscar)

    # phonopy phonon instance
    phonon = Phonopy(bulk, supercell_matrix, factor=VaspToTHz)
    phonon.generate_displacements(distance=0.01)
    # symmetry = phonon.get_symmetry()

    # report
    # print "Space group:", symmetry.get_international_table()
    # phonon.print_displacements()
    # supercells = phonon.get_supercells_with_displacements()

    # set force constants
    phonon.set_force_constants(force_constants)

    # calc band structure
    # . compute
    phonon.set_qpoints_phonon(
        qpoints, is_eigenvectors=True,
        write_dynamical_matrices=False)  # , factor=VaspToTHz)

    # output band structure
    # phonon.write_yaml_qpoints_phonon()

    # . get data
    freq, pols = phonon.get_qpoints_phonon()
    freq = freq * freq2omega
    pols = np.transpose(pols, (0, 2, 1))
    pols.shape = pols.shape[:-1] + (-1, 3)
    # pols: Q, branch, atom, xyz

    print("* Discarding negative freqencies")
    freq[freq < 0] = 0
    # min = np.min(freq)
    # if min < 0: freq += -min

    # correction for pols
    print("* Fixing polarizations")
    nq, nbr, natoms, three = pols.shape
    assert three is 3
    atoms = vasp.read_vasp(poscar)
    positions = atoms.get_scaled_positions()
    # correct polarization vectors
    # the phase factor is needed. see the notebook tests/phonon/phase-factor.ipynb
    # c.c. is needed at the very end because of another convention difference between phonopy and pybvk codes.
    # without c.c., we have to use exp(-j Q dot r) instead of exp(j Q dot r) in calculation of dynamical factors
    for iatom in range(natoms):
        qdotr = np.dot(qpoints, positions[iatom]) * 2 * np.pi
        phase = np.exp(1j * qdotr)
        pols[:, :, iatom, :] *= phase[:, np.newaxis, np.newaxis]
        norms = np.linalg.norm(pols, axis=-1)
        pols /= norms[:, :, :, np.newaxis]
        continue
    pols = np.conj(pols)
    #
    return qpoints, freq, pols
Пример #28
0
                continue
            tmp = float(l[30:45]) + 19.433700000000
            newline = l[:30] + f'{tmp}' + l[45:]
            if n % 202 == 91 or n % 202 == 168:
                new.write(l.replace('O', 'F'))
                new.write(newline.replace('O', 'F'))
            elif n % 202 == 46 or n % 202 == 47:
                new.write(l.replace('La', 'Fe'))
                new.write(newline.replace('La', 'Fe'))
            else:
                new.write(l)
                new.write(newline)
            # tmp = float(l[30:45]) + 15
            # newline = l[:30] + f'{tmp}' + l[45:]

# %%
tmp = float(l[30:45]) + 19.433700000000
newline = l[:30] + f'{tmp}' + l[45:]

# %%
from pymatgen import Structure

from phonopy import Phonopy

p = Phonopy()

p.generate_displacements(distance=)

s = Structure.from_file()

s.tra
Пример #29
0
def calculate_phonon(atoms,
                     calc=None,
                     forces_set_file=None,
                     ndim=np.eye(3),
                     primitive_matrix=np.eye(3),
                     distance=0.01,
                     factor=VaspToTHz,
                     is_plusminus='auto',
                     is_symmetry=True,
                     symprec=1e-5,
                     func=None,
                     prepare_initial_wavecar=False,
                     skip=None,
                     restart=True,
                     parallel=True,
                     sc_mag=None,
                     **func_args):
    """
    """
    if 'magmoms' in atoms.arrays or 'initial_magmoms' in atoms.arrays:
        is_mag = True
    else:
        is_mag = False
    print("is_mag: ", is_mag)
    # 1. get displacements and supercells
    if calc is not None:
        atoms.set_calculator(calc)
    # bulk = PhonopyAtoms(atoms=atoms)
    if is_mag:
        bulk = PhonopyAtoms(
            symbols=atoms.get_chemical_symbols(),
            scaled_positions=atoms.get_scaled_positions(),
            cell=atoms.get_cell(),
            magmoms=atoms.arrays['initial_magmoms'],
        )
    else:
        bulk = PhonopyAtoms(symbols=atoms.get_chemical_symbols(),
                            scaled_positions=atoms.get_scaled_positions(),
                            cell=atoms.get_cell())

    phonon = Phonopy(bulk,
                     ndim,
                     primitive_matrix=primitive_matrix,
                     factor=factor,
                     symprec=symprec)
    phonon.generate_displacements(distance=distance, is_plusminus=is_plusminus)
    disps = phonon.get_displacements()
    for d in disps:
        print(("[phonopy] %d %s" % (d[0], d[1:])))
    supercell0 = phonon.get_supercell()
    supercells = phonon.get_supercells_with_displacements()
    #write_supercells_with_displacements(supercell0, supercells)
    write_disp_yaml(disps, supercell0)

    # 2. calculated forces.
    if forces_set_file is not None:
        symmetry = phonon.get_symmetry()
        set_of_forces = parse_FORCE_SETS(
            is_translational_invariance=False,
            filename=forces_set_file)  # ['first_atoms']
        # set_of_forces=np.array(set_of_forces)
        #set_of_forces=[np.asarray(f) for f in set_of_forces]
        phonon.set_displacement_dataset(set_of_forces)
        phonon.produce_force_constants()
    else:
        # initialize set of forces
        if restart and os.path.exists('forces_set.pickle'):
            try:
                with open("forces_set.pickle", 'rb') as myfile:
                    set_of_forces = pickle.load(myfile)
                iskip = len(set_of_forces) - 1
            except:
                set_of_forces = []
                iskip = -1
        else:
            set_of_forces = []
            iskip = -1

        if prepare_initial_wavecar and skip is None:
            scell = supercell0
            cell = Atoms(symbols=scell.get_chemical_symbols(),
                         scaled_positions=scell.get_scaled_positions(),
                         cell=scell.get_cell(),
                         pbc=True)
            if is_mag:
                cell.set_initial_magnetic_moments(sc_mag)
            write('Supercell.cif', cell)
            mcalc = copy.deepcopy(calc)
            mcalc.set(lwave=True, lcharg=True)
            cell.set_calculator(mcalc)
            dir_name = "SUPERCELL0"
            cur_dir = os.getcwd()
            if not os.path.exists(dir_name):
                os.mkdir(dir_name)
            os.chdir(dir_name)
            mcalc.scf_calculation(cell)
            os.chdir(cur_dir)

        def calc_force(iscell):
            scell = supercells[iscell]
            cell = Atoms(symbols=scell.get_chemical_symbols(),
                         scaled_positions=scell.get_scaled_positions(),
                         cell=scell.get_cell(),
                         pbc=True)
            if is_mag:
                cell.set_initial_magnetic_moments(sc_mag)
            cell.set_calculator(copy.deepcopy(calc))
            dir_name = "PHON_CELL%s" % iscell
            cur_dir = os.getcwd()
            if not os.path.exists(dir_name):
                os.mkdir(dir_name)
            if prepare_initial_wavecar:
                os.system('ln -s %s %s' %
                          (os.path.abspath("SUPERCELL0/WAVECAR"),
                           os.path.join(dir_name, 'WAVECAR')))

            os.chdir(dir_name)
            forces = cell.get_forces()
            print("[Phonopy] Forces: %s" % forces)
            # Do something other than calculating the forces with func.
            # func: func(atoms, calc, func_args)
            if func is not None:
                func(cell, calc, **func_args)
            os.chdir(cur_dir)
            drift_force = forces.sum(axis=0)
            print("[Phonopy] Drift force:", "%11.5f" * 3 % tuple(drift_force))
            # Simple translational invariance
            for force in forces:
                force -= drift_force / forces.shape[0]
            return forces

        if parallel:
            p = Pool()
            set_of_forces = p.map(calc_force,
                                  list(range(iskip, len(supercells))))
        else:
            for iscell, scell in enumerate(supercells):
                if iscell > iskip:
                    fs = calc_force(iscell)
                    set_of_forces.append(fs)
                    with open("forces_set.pickle", 'wb') as myfile:
                        pickle.dump(set_of_forces, myfile)

        phonon.produce_force_constants(forces=np.array(set_of_forces))
    force_constants = phonon.get_force_constants()
    write_FORCE_CONSTANTS(force_constants, filename='FORCE_CONSTANTS')
    #print("[Phonopy] Phonon frequencies at Gamma:")
    # for i, freq in enumerate(phonon.get_frequencies((0, 0, 0))):
    #    print(("[Phonopy] %3d: %10.5f THz" % (i + 1, freq)))  # THz
    #    print(("[Phonopy] %3d: %10.5f cm-1" % (i + 1, freq * 33.35)))  #cm-1
    with open('phonon.pickle', 'wb') as myfile:
        pickle.dump(phonon, myfile)
    phonon.save(settings={'force_constants': True})
    return phonon
Пример #30
0
class PhononBase(TaskElement):
    """PhononBase class

    This is an interface to phonopy.

    """

    def __init__(self,
                 directory=None,
                 name=None,
                 supercell_matrix=None,
                 primitive_matrix=None,
                 distance=None,
                 lattice_tolerance=None,
                 force_tolerance=None,
                 pressure_target=None,
                 stress_tolerance=None,
                 max_increase=None,
                 max_iteration=None,
                 min_iteration=None,
                 traverse=False,
                 is_cell_relaxed=False):

        TaskElement.__init__(self)

        self._directory = directory
        if not name:
            self._name = directory
        else:
            self._name = name
        self._task_type = "phonon"
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._distance = distance
        self._lattice_tolerance = lattice_tolerance
        self._pressure_target = pressure_target
        self._stress_tolerance = stress_tolerance
        self._force_tolerance = force_tolerance
        self._max_increase = max_increase
        self._max_iteration = max_iteration
        self._min_iteration = min_iteration
        self._traverse = traverse
        self._is_cell_relaxed = is_cell_relaxed

        self._stage = 0
        self._tasks = []

        self._energy = None
        self._cell = None
        self._phonon = None # Phonopy object

    def get_phonon(self):
        return self._phonon

    def get_cell(self):
        if self._is_cell_relaxed:
            return self._cell
        else:
            return self._phonon_tasks[0].get_cell()

    def get_energy(self):
        """Return energies at geometry optimization steps"""
        return self._energy

    def set_status(self):
        done = True
        terminate = False
        for task in self._tasks:
            done &= task.done()
            if task.get_status() == "terminate":
                terminate = True
        if done:
            if terminate:
                self._status = "terminate"
            else:
                self._status = "next"

        self._write_yaml()

    def begin(self):
        if not self._job:
            print "set_job has to be executed."
            raise

        self._overwrite_settings()

        if self._is_cell_relaxed:
            self._phonon_tasks = [None]
            self._set_stage1()
        else:
            self._set_stage0()

    def end(self):
        pass

    def done(self):
        return ("terminate" in self._status or 
                "done" in self._status or
                "next" in self._status)

    def next(self):
        if self._stage == 0:
            if "next" in self._status:
                self._energy = self._tasks[0].get_energy()
                self._comment = "%s\\n%f" % (
                    self._tasks[0].get_space_group()['international_standard'],
                    self._energy)
                self._set_stage1()
                return self._tasks
            elif "terminate" in self._status and self._traverse == "restart":
                self._traverse = False
                self._set_stage0()
                return self._tasks
            else:
                raise StopIteration
        else: # task 1..n: displaced supercells
            if "next" in self._status:
                self._status = "done"
                forces = []
                for task in self._phonon_tasks[1:]:
                    forces.append(task.get_properties()['forces'][-1])
                self._write_FORCE_SETS(forces)
                self._phonon.set_post_process(self._primitive_matrix,
                                              forces,
                                              force_constants_decimals=14)
                self._tasks = []
                raise StopIteration
            elif "terminate" in self._status and self._traverse == "restart":
                self._traverse = False
                disp_terminated = []
                for i, task in enumerate(self._tasks):
                    if task.get_status() == "terminate":
                        disp_terminated.append(i)
                tasks = self._get_displacement_tasks()[1:]
                self._tasks = []
                for i in disp_terminated:
                    self._tasks.append(tasks[i])
                    self._phonon_tasks[i + 1] = tasks[i]
                self._status = "displacements"
                return self._tasks
            else:
                raise StopIteration

    def _set_stage0(self):
        self._status = "equilibrium"
        task = self._get_equilibrium_task()
        self._phonon_tasks = [task]
        self._tasks = [task]
        
    def _set_stage1(self):
        self._stage = 1
        self._status = "displacements"
        self._set_phonon()
        self._tasks = self._get_displacement_tasks()[1:]
        self._phonon_tasks += self._tasks

    def _set_phonon(self):
        cell = self.get_cell()
        phonopy_cell = Atoms(
            cell=cell.get_lattice().T,
            scaled_positions=cell.get_points().T,
            symbols=cell.get_symbols())
        
        self._phonon = Phonopy(phonopy_cell,
                               self._supercell_matrix,
                               is_auto_displacements=False)
        self._phonon.generate_displacements(distance=self._distance,
                                            is_diagonal=False)

        supercell = self._phonon.get_supercell()
        displacements = self._phonon.get_displacements()

        write_poscar(cell, "POSCAR-unitcell")
        write_disp_yaml(displacements, supercell)

    def _write_FORCE_SETS(self, forces):
        displacements = [[x[0], x[1:4]]
                         for x in self._phonon.get_displacements()]
        natom = self._phonon.get_supercell().get_number_of_atoms()
        write_FORCE_SETS("FORCE_SETS",
                         natom,
                         displacements,
                         forces,
                         verbose=False)

    def _write_yaml(self):
        w = open("%s.yaml" % self._directory, 'w')
        if self._phonon_tasks[0]:
            if self._lattice_tolerance is not None:
                w.write("lattice_tolerance: %f\n" % self._lattice_tolerance)
            if self._stress_tolerance is not None:
                w.write("stress_tolerance: %f\n" % self._stress_tolerance)
                w.write("pressure_target: %f\n" % self._pressure_target)
            w.write("force_tolerance: %f\n" % self._force_tolerance)
            w.write("max_increase: %f\n" % self._max_increase)
            w.write("max_iteration: %d\n" % self._max_iteration)
            w.write("min_iteration: %d\n" % self._min_iteration)
            w.write("supercell_matrix:\n")
            for row in self._supercell_matrix:
                w.write("- [ %3d, %3d, %3d ]\n" % tuple(row))
            w.write("primitive_matrix:\n")
            for row in self._primitive_matrix:
                w.write("- [ %6.3f, %6.3f, %6.3f ]\n" % tuple(row))
            w.write("distance: %f\n" % self._distance)
            w.write("iteration: %d\n" % self._phonon_tasks[0].get_stage())
            if self._energy:
                w.write("electric_total_energy: %20.10f\n" % self._energy)
        w.write("status: %s\n" % self._status)
        w.write("tasks:\n")
        for task in self._phonon_tasks:
            if task and task.get_status():
                w.write("- name:   %s\n" % task.get_name())
                w.write("  status: %s\n" % task.get_status())
        w.close()
Пример #31
0
                                      (0, 0.5, 0.5),
                                      (0.5, 0, 0.5),
                                      (0.5, 0.5, 0),
                                      (0.25, 0.25, 0.25),
                                      (0.25, 0.75, 0.75),
                                      (0.75, 0.25, 0.75),
                                      (0.75, 0.75, 0.25)])
calc = GPAW(mode=PW(300),
            kpts={'size': (4, 4, 4)})

phonon = Phonopy(bulk,
                 [[1,0,0], [0,1,0], [0,0,1]],
                 primitive_matrix=[[0, 0.5, 0.5],
                                   [0.5, 0, 0.5],
                                   [0.5, 0.5, 0]])
phonon.generate_displacements(distance=0.01)
print("[Phonopy] Atomic displacements:")
disps = phonon.get_displacements()
for d in disps:
    print ("[Phonopy] %d %s" % (d[0], d[1:]))
supercells = phonon.get_supercells_with_displacements()

# Force calculations by calculator
set_of_forces = []
for scell in supercells:
    cell = Atoms(symbols=scell.get_chemical_symbols(),
                 scaled_positions=scell.get_scaled_positions(),
                 cell=scell.get_cell(),
                 pbc=True)
    cell.set_calculator(calc)
    forces = cell.get_forces()
Пример #32
0
class PhononBase(TaskElement):
    """PhononBase class

    This is an interface to phonopy.

    """

    def __init__(self,
                 directory=None,
                 name=None,
                 supercell_matrix=None,
                 primitive_matrix=None,
                 distance=None,
                 displace_plusminus='auto',
                 displace_diagonal=False,
                 lattice_tolerance=None,
                 force_tolerance=None,
                 pressure_target=None,
                 stress_tolerance=None,
                 max_increase=None,
                 max_iteration=None,
                 min_iteration=None,
                 is_cell_relaxed=False,
                 stop_condition=None,
                 traverse=False):

        TaskElement.__init__(self)

        self._directory = directory
        if not name:
            self._name = directory
        else:
            self._name = name
        self._task_type = "phonon"
        self._supercell_matrix = supercell_matrix
        self._primitive_matrix = primitive_matrix
        self._distance = distance
        self._displace_plusminus = displace_plusminus
        self._displace_diagonal = displace_diagonal
        self._lattice_tolerance = lattice_tolerance
        self._pressure_target = pressure_target
        self._stress_tolerance = stress_tolerance
        self._force_tolerance = force_tolerance
        self._max_increase = max_increase
        self._max_iteration = max_iteration
        self._min_iteration = min_iteration
        self._is_cell_relaxed = is_cell_relaxed
        self._stop_condition = stop_condition
        self._traverse = traverse

        self._stage = 0
        self._tasks = []

        self._energy = None
        self._space_group = None
        self._cell = None
        self._phonon = None # Phonopy object
        self._phonon_tasks = None # Phonopy object

    def get_phonon(self):
        return self._phonon

    def get_cell(self):
        if self._is_cell_relaxed:
            return self._cell
        else:
            return self._phonon_tasks[0].get_cell()

    def get_energy(self):
        """Return energies at geometry optimization steps"""
        return self._energy

    def get_space_group(self):
        return self._space_group
        
    def set_status(self):
        if self._stage == 0:
            task = self._tasks[0]
            if task.done():
                self._space_group = task.get_space_group()
                status = task.get_status()
                if status == "done":
                    if not self._evaluate_stop_condition():
                        self._status = "next"
                else:
                    self._status = status
        else:
            done = True
            terminate = True
            for task in self._tasks:
                done &= task.done()
                terminate &= (task.get_status() == "terminate")
                
            if done:
                if terminate:
                    self._status = "terminate"
                else:
                    self._status = "next"

        self._write_yaml()

    def begin(self):
        if not self._job:
            print "set_job has to be executed."
            raise

        self._overwrite_settings()

        if self._is_cell_relaxed:
            self._phonon_tasks = [None]
            self._set_stage1()
        else:
            self._set_stage0()

    def done(self):
        return (self._status == "terminate" or
                self._status == "done" or
                self._status == "max_iteration" or
                self._status == "low_symmetry" or
                self._status == "next")

    def next(self):
        if self._stage == 0:
            if self._status == "next":
                self._energy = self._tasks[0].get_energy()
                num_atom = len(self._tasks[0].get_cell().get_symbols())
                self._comment = self._space_group['international_standard']
                self._comment += "\\n%f/%d" % (self._energy, num_atom)
                self._set_stage1()
                return self._tasks
            elif (self._status == "terminate" and self._traverse == "restart"):
                self._traverse = False
                self._set_stage0()
                return self._tasks
                
        else: # task 1..n: displaced supercells
            if self._status == "next":
                self._status = "done"
                forces = []
                for task in self._tasks:
                    forces.append(task.get_properties()['forces'][-1])
                self._phonon.produce_force_constants(forces)
                write_FORCE_SETS(self._phonon.get_displacement_dataset())
                self._tasks = []
            elif self._status == "terminate" and self._traverse == "restart":
                self._traverse = False
                disp_terminated = []
                for i, task in enumerate(self._tasks):
                    if task.get_status() == "terminate":
                        disp_terminated.append(i)
                tasks = self._get_displacement_tasks()
                self._tasks = []
                for i in disp_terminated:
                    self._tasks.append(tasks[i])
                    self._phonon_tasks[i + 1] = tasks[i]
                self._status = "displacements"
                return self._tasks
                
        self._write_yaml()
            
        raise StopIteration

    def _set_stage0(self):
        self._status = "equilibrium"
        task = self._get_equilibrium_task()
        self._phonon_tasks = [task]
        self._tasks = [task]
        
    def _set_stage1(self):
        self._stage = 1
        self._status = "displacements"
        self._set_phonon()
        self._tasks = self._get_displacement_tasks()
        self._phonon_tasks += self._tasks

    def _evaluate_stop_condition(self):
        if self._stop_condition:
            if "symmetry_operations" in self._stop_condition:
                num_ops = len(self._space_group['rotations'])
                if (num_ops <
                    self._stop_condition['symmetry_operations']):
                    self._status = "low_symmetry"
                    return True
                    
        return False
        
    def _set_phonon(self):
        cell = self.get_cell()
        phonopy_cell = cell2atoms(cell)
        self._phonon = Phonopy(phonopy_cell,
                               self._supercell_matrix,
                               primitive_matrix=self._primitive_matrix,
                               is_auto_displacements=False,
                               dynamical_matrix_decimals=14,
                               force_constants_decimals=14)
        self._phonon.generate_displacements(
            distance=self._distance,
            is_plusminus=self._displace_plusminus,
            is_diagonal=self._displace_diagonal)
        supercell = self._phonon.get_supercell()
        displacements = self._phonon.get_displacements()

        write_poscar(cell, "POSCAR-unitcell")
        write_disp_yaml(displacements, supercell)

    def _write_yaml(self):
        w = open("%s.yaml" % self._directory, 'w')
        w.write("supercell_matrix:\n")
        for row in self._supercell_matrix:
            w.write("- [ %3d, %3d, %3d ]\n" % tuple(row))
        w.write("primitive_matrix:\n")
        for row in self._primitive_matrix:
            w.write("- [ %6.3f, %6.3f, %6.3f ]\n" % tuple(row))
        w.write("distance: %f\n" % self._distance)
        
        if self._phonon_tasks[0]:
            if self._lattice_tolerance is not None:
                w.write("lattice_tolerance: %f\n" % self._lattice_tolerance)
            if self._stress_tolerance is not None:
                w.write("stress_tolerance: %f\n" % self._stress_tolerance)
                w.write("pressure_target: %f\n" % self._pressure_target)
            w.write("force_tolerance: %f\n" % self._force_tolerance)
            if self._max_increase is None:
                w.write("max_increase: unset\n")
            else:
                w.write("max_increase: %f\n" % self._max_increase)
            w.write("max_iteration: %d\n" % self._max_iteration)
            w.write("min_iteration: %d\n" % self._min_iteration)
            w.write("iteration: %d\n" % self._phonon_tasks[0].get_stage())
            if self._energy:
                w.write("electric_total_energy: %20.10f\n" % self._energy)
                
        w.write("status: %s\n" % self._status)
        w.write("tasks:\n")
        for task in self._phonon_tasks:
            if task and task.get_status():
                w.write("- name:   %s\n" % task.get_name())
                w.write("  status: %s\n" % task.get_status())
        w.close()
Пример #33
0
class PhononBase(TaskElement, PhononYaml):
    """PhononBase class

    This is an interface to phonopy.

    """

    def __init__(self,
                 directory=None,
                 name=None,
                 supercell_matrix=None,
                 primitive_matrix=None,
                 nac=False,
                 distance=None,
                 displace_plusminus='auto',
                 displace_diagonal=False,
                 lattice_tolerance=None,
                 force_tolerance=None,
                 pressure_target=None,
                 stress_tolerance=None,
                 max_increase=None,
                 max_iteration=None,
                 min_iteration=None,
                 is_cell_relaxed=False,
                 max_num_atoms=None,
                 stop_condition=None,
                 symmetry_tolerance=None,
                 traverse=False):

        TaskElement.__init__(self)

        self._directory = directory
        if not name:
            self._name = directory
        else:
            self._name = name
        self._task_type = "phonon"
        self._supercell_matrix = supercell_matrix
        if self._supercell_matrix is None:
            self._primitive_matrix = np.eye(3, dtype='double')
        else:
            self._primitive_matrix = primitive_matrix
        self._nac = nac
        self._distance = distance
        self._displace_plusminus = displace_plusminus
        self._displace_diagonal = displace_diagonal
        self._lattice_tolerance = lattice_tolerance
        self._pressure_target = pressure_target
        self._stress_tolerance = stress_tolerance
        self._force_tolerance = force_tolerance
        self._max_increase = max_increase
        self._max_iteration = max_iteration
        self._min_iteration = min_iteration
        self._is_cell_relaxed = is_cell_relaxed
        self._max_num_atoms = max_num_atoms
        self._stop_condition = stop_condition
        self._symmetry_tolerance = symmetry_tolerance
        self._traverse = traverse

        self._stage = 0
        self._tasks = []

        self._energy = None
        self._born = None
        self._epsilon = None

        self._space_group = None
        self._cell = None
        self._phonon = None # Phonopy object
        self._all_tasks = None

        self._try_collect_forces = True

    def get_phonon(self):
        return self._phonon

    def get_cell(self):
        if self._is_cell_relaxed:
            return self._cell
        else:
            return self._all_tasks[0].get_cell()

    def get_energy(self):
        """Return energies at geometry optimization steps"""
        return self._energy

    def get_space_group(self):
        return self._space_group

    def set_status(self):
        if self._stage == 0:
            task = self._tasks[0]
            if task.done():
                self._space_group = task.get_space_group()
                status = task.get_status()
                if status == "done":
                    if not self._evaluate_stop_condition():
                        self._status = "next"
                else:
                    self._status = status
        else:
            done = True
            terminate = False
            for i, task in enumerate(self._tasks):
                done &= task.done()
                if (task.get_status() == "terminate" or
                    task.get_status() == "max_iteration"):
                    terminate = True
            if done:
                if terminate:
                    self._status = "terminate"
                else:
                    self._status = "next"

        self._write_yaml()

    def begin(self):
        if not self._job:
            print("set_job has to be executed.")
            raise RuntimeError

        if self._is_cell_relaxed:
            self._all_tasks = [None]
            self._set_stage1()
        else:
            self._set_stage0()

    def done(self):
        return (self._status == "terminate" or
                self._status == "done" or
                self._status == "max_iteration" or
                self._status == "low_symmetry" or
                self._status == "force_collection_failure" or
                self._status == "next")

    def __next__(self):
        return self.next()

    def next(self):
        if self._stage == 0:
            if self._status == "next":
                self._energy = self._tasks[0].get_energy()
                num_atom = len(self._tasks[0].get_cell().get_symbols())
                self._comment = self._space_group['international']
                self._comment += "\\n%f/%d" % (self._energy, num_atom)
                self._set_stage1()
                return self._tasks
            elif (self._status == "terminate" and self._traverse == "restart"):
                self._traverse = False
                self._set_stage0()
                return self._tasks

        elif self._stage == 1: # task 1..n: displaced supercells
            if self._status == "next":
                if self._collect_forces():
                    if self._nac:
                        self._set_stage2()
                        return self._tasks
                    else:
                        self._status = "done"
                else:
                    if self._try_collect_forces:
                        self._status = "displacements"
                        self._log += ("Collection of forces failed. "
                                      "Try once more.\n")
                        self._try_collect_forces = False
                        raise StopIteration
                    else:
                        self._status = "force_collection_failure"
            elif self._status == "terminate" and self._traverse == "restart":
                self._traverse = False
                disp_terminated = []
                for i, task in enumerate(self._tasks):
                    if task.get_status() == "terminate":
                        disp_terminated.append(i)
                tasks = self._get_displacement_tasks()
                self._tasks = []
                for i in disp_terminated:
                    self._tasks.append(tasks[i])
                    self._all_tasks[i + 1] = tasks[i]
                self._status = "displacements"
                return self._tasks
        elif self._stage == 2:
            if self._status == "next":
                self._status = "done"
                self._set_born_and_epsilon()
            elif self._status == "terminate" and self._traverse == "restart":
                self._traverse = False
                self._all_tasks.pop()
                self._set_stage2()
        else:
            pass

        self._tasks = []
        self._write_yaml()
        raise StopIteration

    def _set_stage0(self):
        self._status = "equilibrium"
        task = self._get_equilibrium_task()
        self._all_tasks = [task]
        self._tasks = [task]

    def _set_stage1(self):
        self._stage = 1
        self._status = "displacements"
        self._set_phonon()
        self._tasks = self._get_displacement_tasks()
        self._all_tasks += self._tasks

    def _set_stage2(self):
        self._stage = 2
        self._status = "nac"
        if self._nac == "relax":
            nac_task = self._get_nac_task(is_cell_relaxed=False)
        else:
            nac_task = self._get_nac_task()
        self._tasks = [nac_task]
        self._all_tasks += self._tasks

    def _collect_forces(self):
        forces = []
        for task in self._tasks:
            forces.append(task.get_properties()['forces'][-1])
        if self._phonon.produce_force_constants(forces=forces):
            write_FORCE_SETS(self._phonon.get_displacement_dataset())
            return True
        else:
            # This can be due to delay of writting file to file system.
            return False

    def _set_born_and_epsilon(self):
        nac_task = self._tasks[0]
        born = nac_task.get_born_effective_charge()
        epsilon = nac_task.get_dielectric_constant()

        indep_atoms = self._phonon.get_symmetry().get_independent_atoms()
        supercell = self._phonon.get_supercell()
        s2u = supercell.get_supercell_to_unitcell_map()
        u2u = supercell.get_unitcell_to_unitcell_map()
        indep_atoms_u = [u2u[i] for i in s2u[indep_atoms]]

        if born is not None and epsilon is not None:
            self._born = born
            self._epsilon = epsilon
            header = "# epsilon and Z* of atoms "
            header += ' '.join(["%d" % (n + 1) for n in indep_atoms_u])
            lines = [header]
            lines.append(("%13.8f" * 9) % tuple(epsilon.flatten()))
            for z in born[indep_atoms_u]:
                lines.append(("%13.8f" * 9) % tuple(z.flatten()))
            with open("BORN", 'w') as w:
                w.write('\n'.join(lines))

    def _evaluate_stop_condition(self):
        if self._stop_condition:
            if "symmetry_operations" in self._stop_condition:
                num_ops = len(self._space_group['rotations'])
                if (num_ops <
                    self._stop_condition['symmetry_operations']):
                    self._status = "low_symmetry"
                    return True

        return False

    def _set_phonon(self):
        if self._supercell_matrix is None:
            cell = sort_cell_by_symbols(
                get_crystallographic_cell(self.get_cell()))
            self._supercell_matrix = estimate_supercell_matrix(
                cell,
                max_num_atoms=self._max_num_atoms)
        else:
            cell = self.get_cell()

        phonopy_cell = cell2atoms(cell)
        self._phonon = Phonopy(phonopy_cell,
                               self._supercell_matrix,
                               primitive_matrix=self._primitive_matrix,
                               dynamical_matrix_decimals=14,
                               force_constants_decimals=14,
                               symprec=self._symmetry_tolerance)
        self._phonon.generate_displacements(
            distance=self._distance,
            is_plusminus=self._displace_plusminus,
            is_diagonal=self._displace_diagonal)
        supercell = self._phonon.get_supercell()
        displacements = self._phonon.get_displacements()

        write_poscar(cell, filename="POSCAR-unitcell")
        write_poscar_yaml(cell, filename="POSCAR-unitcell.yaml")
        write_disp_yaml(displacements, supercell)

    def get_yaml_lines(self):
        lines = TaskElement.get_yaml_lines(self)
        if self._is_cell_relaxed:
            cell = self._cell
        else:
            cell = self.get_cell()
        lines += self._get_phonon_yaml_lines(cell)
        if self._all_tasks[0] is not None:
            if self._energy:
                lines.append("electric_total_energy: %20.10f" % self._energy)

        return lines
Пример #34
0
def phonopy_run(phonon, single=True, filename='FORCE_SETS'):
    """Run the phonon calculations, using PhonoPy.
    
    The force constants are then stored in the Phonon ASE object.
          
    input:
    
      phonon: ASE Phonon object with Atoms and Calculator
      single: when True, the forces are computed only for a single step, and then
              exit. This allows to split the loop in independent iterations. When
              calling again the 'run' method, already computed steps are ignored,
              missing steps are completed, until no more are needed. When set to
              False, all steps are done in a row.
    
    output:
    
      True when a calculation step was performed, False otherwise or no more is needed.
      nb_of_iterations: the number of steps remaining

    """

    from phonopy import Phonopy
    from phonopy.structure.atoms import Atoms as PAtoms
    from phonopy.structure.atoms import PhonopyAtoms
    import phonopy.file_IO as file_IO

    # we first look if an existing phonon pickle exists. This is the case if we
    # are running with iterative calls while return value is True. The first call
    # will then create the objects, which are subsequently updated until False.

    # Set calculator if provided
    # assert phonon.calc is not None, "Provide calculator in Phonon __init__ method"

    # Atoms in the supercell -- repeated in the lattice vector directions
    # beginning with the last
    supercell = phonon.atoms * phonon.N_c

    # create a PhonopyAtoms object
    cell = PhonopyAtoms(phonon.atoms.get_chemical_symbols(),
                        positions=phonon.atoms.get_positions(),
                        cell=phonon.atoms.get_cell(),
                        magmoms=None)

    # is there an existing PhonoPy calculation ?
    # using factor=6.46541380e-2=VaspToeV
    if os.path.exists('FORCE_SETS'):
        phonpy = Phonopy(cell,
                         numpy.diag(phonon.N_c),
                         primitive_matrix=None,
                         dynamical_matrix_decimals=None,
                         force_constants_decimals=None,
                         symprec=1e-05,
                         is_symmetry=True,
                         use_lapack_solver=False,
                         log_level=1)
        force_sets = file_IO.parse_FORCE_SETS(filename='FORCE_SETS')
        phonpy.set_displacement_dataset(force_sets)
        # inactivate magmoms in supercell as some calculators do not provide that
        phonpy._supercell.magmoms = None
        phonpy.produce_force_constants(calculate_full_force_constants=False)
    else:
        # create a PhonoPy Phonon object.
        phonpy = Phonopy(cell, numpy.diag(phonon.N_c))
        # generate displacements (minimal set)
        phonpy.generate_displacements(distance=0.01)
        # iterative call for all displacements
        set_of_forces, flag, nb_of_iterations = phonopy_run_calculate(
            phonon, phonpy, supercell, single)

        if flag is True:
            return nb_of_iterations  # some more work is required

        sys.stdout.write('[ASE/Phonopy] Computing force constants\n')
        # use symmetry to derive forces in equivalent displacements
        phonpy.produce_force_constants(forces=set_of_forces)

        # generate disp.yaml and FORCE_SETS (for later use)
        displacements = phonpy.get_displacements()
        directions = phonpy.get_displacement_directions()
        file_IO.write_disp_yaml(displacements,
                                phonpy.get_supercell(),
                                directions=directions)
        file_IO.write_FORCE_SETS(phonpy.get_displacement_dataset())

    # store as additional data in atoms 'info'
    phonon.atoms.info["phonopy"] = phonpy

    # save the PhonoPy object
    fid = opencew("phonopy.pkl")
    if fid is not None and rank == 0:
        print("[ASE/Phonopy] Writing %s" % "phonopy.pkl")
        pickle.dump(phonpy, fid, protocol=2)
        fid.close()

    # transfer results to the ASE phonon object
    # Number of atoms (primitive cell)
    natoms = len(phonon.indices)
    # Number of unit cells (supercell)
    N = numpy.prod(phonon.N_c)

    # Phonopy: force_constants size is [N*natoms,N*natoms,3,3]
    # Phi[i,j,a,b] with [i,j = atom in supercell] and [a,b=xyz]
    force_constants = phonpy.get_force_constants()
    # the atoms [i] which are moved are in the first cell of the supercell, i.e.Ni=0
    # the forces are then stored for all atoms [Nj,j] as [3,3] matrices

    # we compute the sum on all supercells, which all contain n atoms.
    C_N = numpy.zeros((N, 3 * natoms, 3 * natoms), dtype=complex)
    Ni = 0
    for Nj in range(N):
        for ni in range(natoms):
            Nni = ni
            for nj in range(natoms):
                # compute Nn indices
                Nnj = Nj * natoms + nj
                # get fc 3x3 matrix
                C_N[Nj, (3 * ni):(3 * ni + 3),
                    (3 * nj):(3 * nj + 3)] += force_constants[Nni][Nnj]

    # convert to ASE storage
    # ASE: phonon.C_N size is be [N, 3*natoms, 3*natoms]
    # Phi[i,j] = Phi[j,i]
    phonon.C_N = C_N

    # fill dynamical matrix (mass prefactor)
    phonon.D_N = phonon.C_N.copy()

    # Add mass prefactor
    m_a = phonon.atoms.get_masses()
    phonon.m_inv_x = numpy.repeat(m_a[phonon.indices]**-0.5, 3)
    M_inv = numpy.outer(phonon.m_inv_x, phonon.m_inv_x)
    for D in phonon.D_N:
        D *= M_inv

    return 0  # nothing left to do
Пример #35
0
    def phonons(self,
                atoms=None,
                lammps_cmd="",
                enforce_c_size=15.0,
                parameters={}):
        """Make Phonon calculation setup."""
        from phonopy import Phonopy
        from phonopy.file_IO import (
            #    parse_FORCE_CONSTANTS,
            write_FORCE_CONSTANTS, )

        bulk = atoms.phonopy_converter()

        dim = get_supercell_dims(atoms, enforce_c_size=enforce_c_size)
        atoms = atoms.make_supercell([dim[0], dim[1], dim[2]])

        Poscar(atoms).write_file("POSCAR")

        atoms = atoms.make_supercell_matrix([dim[0], dim[1], dim[2]])
        Poscar(atoms).write_file("POSCAR-Super.vasp")

        phonon = Phonopy(bulk,
                         [[dim[0], 0, 0], [0, dim[1], 0], [0, 0, dim[2]]])
        print("[Phonopy] Atomic displacements1:", bulk)
        print("[Phonopy] Atomic displacements2:", phonon, dim[0], dim[1],
              dim[2])
        phonon.generate_displacements(distance=0.03)
        disps = phonon.get_displacements()
        print("[Phonopy] Atomic displacements3:", disps)
        for d in disps:
            print("[Phonopy]", d[0], d[1:])
        supercells = phonon.get_supercells_with_displacements()

        # Force calculations by calculator
        set_of_forces = []
        disp = 0
        from ase import Atoms as AseAtoms

        for scell in supercells:
            ase_atoms = AseAtoms(
                symbols=scell.get_chemical_symbols(),
                scaled_positions=scell.get_scaled_positions(),
                cell=scell.get_cell(),
                pbc=True,
            )
            j_atoms = ase_to_atoms(ase_atoms)
            disp = disp + 1

            parameters["control_file"] = "run0.mod"
            a, b, forces = LammpsJob(
                atoms=j_atoms,
                lammps_cmd=lammps_cmd,
                parameters=parameters,
                jobname="disp-" + str(disp),
            ).runjob()
            print("forces=", forces)
            drift_force = forces.sum(axis=0)
            print("drift forces=", drift_force)
            # Simple translational invariance
            for force in forces:
                force -= drift_force / forces.shape[0]
            set_of_forces.append(forces)
        phonon.produce_force_constants(forces=set_of_forces)

        write_FORCE_CONSTANTS(phonon.get_force_constants(),
                              filename="FORCE_CONSTANTS")
        print()
        print("[Phonopy] Phonon frequencies at Gamma:")