예제 #1
0
def test_general_array_atom_quotient():
    sym = sym_quotient_translational_00_xyz()

    callbacks = symmetry.GeneralArrayCallbacks(['atom'])
    disp_atoms, disp_carts, disp_values = zip(*[
        DispData(0, [ 0.1,    0,    0], data=np.array([ 1.,  2.,  3.])),
        DispData(0, [-0.1,    0,    0], data=np.array([-1., -2., -3.])),
    ])
    derivs = symmetry.expand_derivs_by_symmetry(
            callbacks=callbacks, disp_atoms=disp_atoms, disp_carts=disp_carts, disp_values=disp_values,
            oper_cart_rots=sym.oper_cart_rots, oper_perms=sym.oper_perms, quotient_perms=sym.quotient_perms,
    )
    derivs = np.array(derivs.tolist())
    assert np.allclose(derivs, np.array([[
        [10, 20, 30],  # derivative w.r.t. atom 0 x
        [10, 20, 30],  # derivative w.r.t. atom 0 y
        [10, 20, 30],  # derivative w.r.t. atom 0 z
    ], [
        [30, 10, 20],  # derivative w.r.t. atom 1 x
        [30, 10, 20],  # derivative w.r.t. atom 1 y
        [30, 10, 20],  # derivative w.r.t. atom 1 z
    ], [
        [20, 30, 10],  # derivative w.r.t. atom 2 x
        [20, 30, 10],  # derivative w.r.t. atom 2 y
        [20, 30, 10],  # derivative w.r.t. atom 2 z
    ]]))
예제 #2
0
def test_pure_translation():
    for (description, sym) in [
            ('SEPARATE TRANSLATIONS', sym_quotient_translational_010101()),
            ('EMBEDDED TRANSLATIONS', sym_embedded_translational_010101()),
    ]:
        print(f'TRYING {description}')
        callbacks = symmetry.GeneralArrayCallbacks([])
        disp_atoms, disp_carts, disp_values = zip(*[
            DispData(0, [ 0.1,    0,    0], data=np.array( 1.)),
            DispData(0, [-0.1,    0,    0], data=np.array(-1.)),
            DispData(0, [   0,  0.1,    0], data=np.array( 2.)),
            DispData(0, [   0, -0.1,    0], data=np.array(-2.)),
            DispData(0, [   0,    0,  0.1], data=np.array( 3.)),
            DispData(0, [   0,    0, -0.1], data=np.array(-3.)),
            DispData(1, [ 0.1,    0,    0], data=np.array( 4.)),
            DispData(1, [-0.1,    0,    0], data=np.array(-4.)),
            DispData(1, [   0,  0.1,    0], data=np.array( 5.)),
            DispData(1, [   0, -0.1,    0], data=np.array(-5.)),
            DispData(1, [   0,    0,  0.1], data=np.array( 6.)),
            DispData(1, [   0,    0, -0.1], data=np.array(-6.)),
        ])
        derivs = symmetry.expand_derivs_by_symmetry(
                callbacks=callbacks, disp_atoms=disp_atoms, disp_carts=disp_carts, disp_values=disp_values,
                oper_cart_rots=sym.oper_cart_rots, oper_perms=sym.oper_perms, quotient_perms=sym.quotient_perms,
        )
        derivs = np.array(derivs.tolist())
        assert np.allclose(derivs, np.array([
            [10, 20, 30],  # gradient w.r.t. atom 0
            [40, 50, 60],  # gradient w.r.t. atom 1
            [10, 20, 30],  # gradient w.r.t. atom 2
            [40, 50, 60],  # gradient w.r.t. atom 3
            [10, 20, 30],  # gradient w.r.t. atom 4
            [40, 50, 60],  # gradient w.r.t. atom 5
        ]))
예제 #3
0
def test_general_array_atom():
    sym = sym_xyz_3_atom()
    callbacks = symmetry.GeneralArrayCallbacks(['atom'])
    disp_atoms, disp_carts, disp_values = zip(*[
        # because the operator is no longer in the site symmetry, we need more disps
        DispData(0, [ 0.1,    0,    0], data=np.array([ 2.,  3.,  4.])),
        DispData(0, [-0.1,    0,    0], data=np.array([-2., -3., -4.])),
        DispData(0, [   0,  0.1,    0], data=np.array([ 5.,  6.,  7.])),
        DispData(0, [   0, -0.1,    0], data=np.array([-5., -6., -7.])),
        DispData(0, [   0,    0,  0.1], data=np.array([ 8.,  9.,  10.])),
        DispData(0, [   0,    0, -0.1], data=np.array([-8., -9., -10.])),
    ])
    print(sym.oper_perms)
    derivs = symmetry.expand_derivs_by_symmetry(
            callbacks=callbacks, disp_atoms=disp_atoms, disp_carts=disp_carts, disp_values=disp_values,
            oper_cart_rots=sym.oper_cart_rots, oper_perms=sym.oper_perms, quotient_perms=sym.quotient_perms,
    )
    derivs = np.array(derivs.tolist())
    assert np.allclose(derivs, np.array([[
        [20, 30,  40],  # deriv w.r.t. atom 0 x
        [50, 60,  70],  # deriv w.r.t. atom 0 y
        [80, 90, 100],  # deriv w.r.t. atom 0 z
    ], [
        [100, 80, 90],  # deriv w.r.t. atom 1 x
        [ 40, 20, 30],  # deriv w.r.t. atom 1 y
        [ 70, 50, 60],  # deriv w.r.t. atom 1 z
    ], [
        [60,  70, 50],  # deriv w.r.t. atom 2 x
        [90, 100, 80],  # deriv w.r.t. atom 2 y
        [30,  40, 20],  # deriv w.r.t. atom 2 z
    ]]))
예제 #4
0
def test_gpaw_grid_C4_z():
    N_c = (5, 5, 3)  # grid dimensions
    nspins = 1

    cart_rot_generator = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]])
    perm_generator = np.array([3, 0, 1, 2])
    op_scc_generator = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 1]])  # gpaw's op_scc is transposed (operates on row vectors)

    oper_cart_rots = test_utils.cyclic_group(cart_rot_generator, compose_rot, make_rot_hashable)
    oper_perms = test_utils.cyclic_group(perm_generator, compose_perm, make_perm_hashable)
    op_scc = test_utils.cyclic_group(op_scc_generator, compose_rot_T, make_rot_hashable)
    ft_sc = np.zeros((4, 3))
    quotient_perms = None
    supercell = (1, 1, 1)

    callbacks = symmetry.GpawLcaoVTCallbacks__from_parts(nspins=nspins, N_c=N_c, op_scc=op_scc, ft_sc=ft_sc, supercell=supercell, pbc_c=True)

    def data_pointed(index_tuple, value):
        """ Creates Vt data with a single nonzero value. """
        array = np.zeros((nspins,) + N_c)
        array[(0,) + index_tuple] = value
        return array
    data_zero = np.zeros((nspins,) + N_c)

    disp_atoms, disp_carts, disp_values = zip(*[
        DispData(0, [ 0.1,    0,    0], data=data_pointed((2, 0, 2),  1.0)),
        DispData(0, [-0.1,    0,    0], data=data_pointed((2, 0, 2), -1.0)),
        DispData(0, [   0,  0.1,    0], data=data_zero),
        DispData(0, [   0, -0.1,    0], data=data_zero),
        DispData(0, [   0,    0,  0.1], data=data_zero),
        DispData(0, [   0,    0, -0.1], data=data_zero),
    ])
    derivs = symmetry.expand_derivs_by_symmetry(
            callbacks=callbacks, disp_atoms=disp_atoms, disp_carts=disp_carts, disp_values=disp_values,
            oper_cart_rots=oper_cart_rots, oper_perms=oper_perms, quotient_perms=quotient_perms,
    )
    derivs = np.array(derivs.tolist())
    expected = np.array([[
        data_pointed((2, 0, 2), 10.0),  # derivative w.r.t. atom 0 x
        data_zero,  # derivative w.r.t. atom 0 y
        data_zero,  # derivative w.r.t. atom 0 z
    ], [
        data_zero,  # derivative w.r.t. atom 1 x
        data_pointed((0, 2, 2), 10.0),  # derivative w.r.t. atom 1 y
        data_zero,  # derivative w.r.t. atom 1 z
    ], [
        data_pointed(((-2)%5, 0, 2), -10.0),  # derivative w.r.t. atom 2 x
        data_zero,  # derivative w.r.t. atom 2 y
        data_zero,  # derivative w.r.t. atom 2 z
    ], [
        data_zero,  # derivative w.r.t. atom 3 x
        data_pointed((0, (-2)%5, 2), -10.0),  # derivative w.r.t. atom 3 y
        data_zero,  # derivative w.r.t. atom 3 z
    ]])
    print('actual', list(zip(*np.where(derivs))))
    print('expected', list(zip(*np.where(expected))))
    np.testing.assert_allclose(derivs, expected)
예제 #5
0
def test_general_array_vec():
    sym = sym_xyz_1_atom()
    callbacks = symmetry.GeneralArrayCallbacks(['cart'])
    disp_atoms, disp_carts, disp_values = zip(*[
        DispData(0, [ 0.1, 0, 0], data=np.array([ 1., 0, 0])),
        DispData(0, [-0.1, 0, 0], data=np.array([-1., 0, 0])),
    ])
    derivs = symmetry.expand_derivs_by_symmetry(
            callbacks=callbacks, disp_atoms=disp_atoms, disp_carts=disp_carts, disp_values=disp_values,
            oper_cart_rots=sym.oper_cart_rots, oper_perms=sym.oper_perms, quotient_perms=sym.quotient_perms,
    )
    derivs = np.array(derivs.tolist())
    assert np.allclose(derivs, np.array([[
        [10, 0, 0],
        [0, 10, 0],
        [0, 0, 10],
    ]]))
예제 #6
0
def do_elph_symmetry(
    data_subdir: str,
    params_fd: dict,
    supercell,
    all_displacements: tp.Iterable[AseDisplacement],
    symmetry_type: tp.Optional[str],
):
    atoms = Cluster(ase.build.bulk('C'))

    # a supercell exactly like ElectronPhononCoupling makes
    supercell_atoms = atoms * supercell
    quotient_perms = list(
        interop.ase_repeat_translational_symmetry_perms(len(atoms), supercell))

    # Make sure the grid matches our calculations (we repeated the grid of the groundstate)
    params_fd = copy.deepcopy(params_fd)
    params_fd['gpts'] = GPAW('gs.gpw').wfs.gd.N_c * list(supercell)
    if 'h' in params_fd:
        del params_fd['h']

    wfs_with_sym = get_wfs_with_sym(params_fd=params_fd,
                                    supercell_atoms=supercell_atoms,
                                    symmetry_type=symmetry_type)
    calc_fd = GPAW(**params_fd)

    # GPAW displaces the center cell for some reason instead of the first cell
    elph = ElectronPhononCoupling(atoms,
                                  calc=calc_fd,
                                  supercell=supercell,
                                  calculate_forces=True)
    displaced_cell_index = elph.offset
    del elph  # just showing that we don't use these anymore
    del calc_fd

    get_displaced_index = lambda prim_atom: displaced_cell_index * len(
        atoms) + prim_atom

    all_displacements = list(all_displacements)
    disp_atoms = [get_displaced_index(disp.atom) for disp in all_displacements]
    disp_carts = [
        disp.cart_displacement(DISPLACEMENT_DIST) for disp in all_displacements
    ]
    disp_values = [
        read_elph_input(data_subdir, disp) for disp in all_displacements
    ]

    full_Vt = np.empty((len(supercell_atoms), 3) + disp_values[0][0].shape)
    full_dH = np.empty((len(supercell_atoms), 3), dtype=object)
    full_forces = np.empty((len(supercell_atoms), 3) + disp_values[0][2].shape)

    lattice = supercell_atoms.get_cell()[...]
    oper_cart_rots = interop.gpaw_op_scc_to_cart_rots(
        wfs_with_sym.kd.symmetry.op_scc, lattice)
    if world.rank == 0:
        full_values = symmetry.expand_derivs_by_symmetry(
            disp_atoms,  # disp -> atom
            disp_carts,  # disp -> 3-vec
            disp_values,  # disp -> T  (displaced value, optionally minus equilibrium value)
            elph_callbacks(wfs_with_sym, supercell),  # how to work with T
            oper_cart_rots,  # oper -> 3x3
            oper_perms=wfs_with_sym.kd.symmetry.a_sa,  # oper -> atom' -> atom
            quotient_perms=quotient_perms,
        )
        for a in range(len(full_values)):
            for c in range(3):
                full_Vt[a][c] = full_values[a][c][0]
                full_dH[a][c] = full_values[a][c][1]
                full_forces[a][c] = full_values[a][c][2]
    else:
        # FIXME
        # the symmetry part is meant to be done in serial but we should return back to
        # our original parallel state after it...
        pass

    return full_Vt, full_dH, full_forces