Beispiel #1
0
def get_fc2(supercell, forces_fc2, disp_dataset, symmetry):
    natom = supercell.get_number_of_atoms()
    force = np.array(forces_fc2, dtype='double', order='C')
    disp = np.zeros_like(force)
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    numbers = supercell.get_atomic_numbers()
    _set_disp_fc2(disp, disp_dataset)
    pure_trans = _collect_pure_translations(symmetry)
    rotations = np.array([np.eye(3, dtype='intc')] * len(pure_trans),
                         dtype='intc',
                         order='C')

    print("------------------------------"
          " ALM FC2 start "
          "------------------------------")

    from alm import ALM
    sys.stdout.flush()
    with ALM(lattice, positions, numbers) as alm:
        nkd = len(np.unique(numbers))
        rcs = -np.ones((1, nkd, nkd), dtype='double')
        alm.find_force_constant(1, rcs)
        alm.set_displacement_and_force(disp, force)
        info = alm.optimize()
        fc2_alm = alm.get_fc(1)

    print("-------------------------------"
          " ALM FC2 end "
          "-------------------------------")

    fc2 = _expand_fc2(fc2_alm, supercell, pure_trans, rotations)

    return fc2
Beispiel #2
0
def get_fc2(supercell,
            forces_fc2,
            disp_dataset,
            symmetry):
    natom = supercell.get_number_of_atoms()
    force = np.array(forces_fc2, dtype='double', order='C')
    disp = np.zeros_like(force)
    lattice = supercell.get_cell()
    positions = supercell.get_scaled_positions()
    numbers = supercell.get_atomic_numbers()
    _set_disp_fc2(disp, disp_dataset)
    pure_trans = _collect_pure_translations(symmetry)
    rotations = np.array([np.eye(3, dtype='intc')] * len(pure_trans),
                         dtype='intc', order='C')

    print("------------------------------"
          " ALM FC2 start "
          "------------------------------")

    from alm import ALM
    with ALM(lattice, positions, numbers, 1) as alm:
        alm.set_displacement_and_force(disp, force)
        alm.run_fitting()
        fc2_alm = alm.get_fc(1)

    print("-------------------------------"
          " ALM FC2 end "
          "-------------------------------")

    fc2 = _expand_fc2(fc2_alm, supercell, pure_trans, rotations)

    return fc2
Beispiel #3
0
def get_fc3(supercell, forces_fc3, disp_dataset, symmetry, log_level=0):
    natom = supercell.get_number_of_atoms()
    assert natom == disp_dataset['natom']

    force = np.array(forces_fc3, dtype='double', order='C')
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    numbers = supercell.get_atomic_numbers()
    disp, indices = _get_alm_disp_fc3(disp_dataset)
    pure_trans = _collect_pure_translations(symmetry)
    rotations = np.array([np.eye(3, dtype='intc')] * len(pure_trans),
                         dtype='intc',
                         order='C')

    if log_level:
        print("------------------------------"
              " ALM FC3 start "
              "------------------------------")

    from alm import ALM
    sys.stdout.flush()
    with ALM(lattice, positions, numbers) as alm:
        alm.set_verbosity(log_level)
        nkd = len(np.unique(numbers))
        if 'cutoff_distance' in disp_dataset:
            cut_d = disp_dataset['cutoff_distance']
            rcs = np.ones((2, nkd, nkd), dtype='double')
            rcs[0] *= -1
            rcs[1] *= cut_d
        else:
            rcs = -np.ones((2, nkd, nkd), dtype='double')
        alm.define(2, rcs)
        alm.set_displacement_and_force(disp[indices], force[indices])
        info = alm.optimize()
        fc2_alm = alm.get_fc(1)
        fc3_alm = alm.get_fc(2)

    if log_level:
        print("-------------------------------"
              " ALM FC3 end "
              "-------------------------------")

    fc2 = _expand_fc2(fc2_alm,
                      supercell,
                      pure_trans,
                      rotations,
                      verbose=(log_level > 0))
    fc3 = _expand_fc3(fc3_alm,
                      supercell,
                      pure_trans,
                      rotations,
                      verbose=(log_level > 0))

    return fc2, fc3
Beispiel #4
0
def get_fc2(supercell,
            primitive,
            disp_dataset,
            atom_list=None,
            alm_options=None,
            log_level=0):
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    numbers = supercell.get_atomic_numbers()
    natom = len(numbers)
    disps, forces = collect_disps_and_forces(disp_dataset)
    p2s_map = primitive.p2s_map
    p2p_map = primitive.p2p_map

    if log_level:
        print("-------------------------------"
              " ALM FC2 start "
              "------------------------------")
        print("ALM by T. Tadano, https://github.com/ttadano/ALM")
        if log_level == 1:
            print("Use -v option to watch detailed ALM log.")

    try:
        from alm import ALM
    except ImportError:
        raise ImportError("ALM python module was not found.")

    sys.stdout.flush()
    with ALM(lattice, positions, numbers) as alm:
        if log_level > 0:
            log_level_alm = log_level - 1
        else:
            log_level_alm = 0
        alm.set_verbosity(log_level_alm)
        alm.define(1)
        alm.set_displacement_and_force(disps, forces)
        alm.optimize()
        fc2 = extract_fc2_from_alm(alm,
                                   natom,
                                   atom_list=atom_list,
                                   p2s_map=p2s_map,
                                   p2p_map=p2p_map)

    if log_level:
        print("--------------------------------"
              " ALM FC2 end "
              "-------------------------------")

    return fc2
Beispiel #5
0
def get_fc3(supercell,
            forces_fc3,
            disp_dataset,
            symmetry):
    natom = supercell.get_number_of_atoms()
    force = np.array(forces_fc3, dtype='double', order='C')
    disp = np.zeros_like(force)
    lattice = supercell.get_cell()
    positions = supercell.get_scaled_positions()
    numbers = supercell.get_atomic_numbers()
    indices = _set_disp_fc3(disp, disp_dataset)
    pure_trans = _collect_pure_translations(symmetry)
    rotations = np.array([np.eye(3, dtype='intc')] * len(pure_trans),
                         dtype='intc', order='C')

    print("------------------------------"
          " ALM FC3 start "
          "------------------------------")

    from alm import ALM
    with ALM(lattice, positions, numbers, 2) as alm:
        alm.set_displacement_and_force(disp[indices], force[indices])
        if 'cutoff_distance' in disp_dataset:
            cut_d = disp_dataset['cutoff_distance']
            nkd = len(np.unique(numbers))
            rcs = np.ones((2, nkd, nkd), dtype='double')
            rcs[0] *= -1
            rcs[1] *= cut_d
            alm.set_cutoff_radii(rcs)
        alm.run_fitting()
        fc2_alm = alm.get_fc(1)
        fc3_alm = alm.get_fc(2)

    print("-------------------------------"
          " ALM FC3 end "
          "-------------------------------")

    fc2 = _expand_fc2(fc2_alm, supercell, pure_trans, rotations)
    fc3 = _expand_fc3(fc3_alm, supercell, pure_trans, rotations)

    return fc2, fc3
Beispiel #6
0
def get_fc2(supercell,
            primitive,
            disp_dataset,
            atom_list=None,
            log_level=0):
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    numbers = supercell.get_atomic_numbers()
    natom = len(numbers)
    disps, forces = _collect_disps_and_forces(disp_dataset)
    p2s_map = primitive.p2s_map
    p2p_map = primitive.p2p_map

    if log_level:
        print("-------------------------------"
              " ALM FC2 start "
              "------------------------------")
        print("ALM by T. Tadano, https://github.com/ttadano/ALM")
        if log_level == 1:
            print("Use -v option to watch detailed ALM log.")

    try:
        from alm import ALM
    except ImportError:
        raise ImportError("ALM python module was not found.")

    sys.stdout.flush()
    with ALM(lattice, positions, numbers) as alm:
        if log_level > 0:
            log_level_alm = log_level - 1
        else:
            log_level_alm = 0
        alm.set_verbosity(log_level_alm)
        alm.define(1)
        alm.set_displacement_and_force(disps, forces)
        alm.optimize()
        p2s_map_alm = alm.getmap_primitive_to_supercell()[0]

        if ((atom_list == p2s_map).all() and
            len(p2s_map_alm) == len(p2s_map) and
            (p2s_map_alm == p2s_map).all()):
            fc2 = np.zeros((len(p2s_map), natom, 3, 3),
                           dtype='double', order='C')
            for fc, indices in zip(*alm.get_fc(1, mode='origin')):
                v1, v2 = indices // 3
                c1, c2 = indices % 3
                fc2[p2p_map[v1], v2, c1, c2] = fc
        else:
            if atom_list is None:
                fc2 = np.zeros((natom, natom, 3, 3), dtype='double', order='C')
                _atom_list = np.arange(natom, dtype=int)
            else:
                fc2 = np.zeros(
                    (len(atom_list), natom, 3, 3), dtype='double', order='C')
                _atom_list = np.array(atom_list, dtype=int)
            for fc, indices in zip(*alm.get_fc(1, mode='all')):
                v1, v2 = indices // 3
                idx = np.where(_atom_list == v1)[0]
                if len(idx) > 0:
                    c1, c2 = indices % 3
                    fc2[idx[0], v2, c1, c2] = fc

    if log_level:
        print("--------------------------------"
              " ALM FC2 end "
              "-------------------------------")

    return fc2
Beispiel #7
0
def get_fc2(supercell, primitive, disp_dataset, atom_list=None, log_level=0):
    lattice = supercell.get_cell().T
    positions = supercell.get_scaled_positions()
    numbers = supercell.get_atomic_numbers()
    natom = len(numbers)
    disps, forces = _collect_disps_and_forces(disp_dataset)
    p2s_map = primitive.p2s_map
    p2p_map = primitive.p2p_map

    if log_level:
        print("-------------------------------"
              " ALM FC2 start "
              "------------------------------")
        print("ALM by T. Tadano, https://github.com/ttadano/ALM")
        if log_level == 1:
            print("Use -v option to watch detailed ALM log.")

    try:
        from alm import ALM
    except ImportError:
        raise ModuleNotFoundError("ALM python module was not found.")

    sys.stdout.flush()
    with ALM(lattice, positions, numbers) as alm:
        if log_level > 0:
            log_level_alm = log_level - 1
        else:
            log_level_alm = 0
        alm.set_verbosity(log_level_alm)
        alm.define(1)
        alm.set_displacement_and_force(disps, forces)
        alm.optimize()
        if (atom_list == p2s_map).all():
            fc2 = np.zeros((len(p2s_map), natom, 3, 3),
                           dtype='double',
                           order='C')
            for fc, indices in zip(*alm.get_fc(1, mode='origin')):
                v1, v2 = indices // 3
                c1, c2 = indices % 3
                fc2[p2p_map[v1], v2, c1, c2] = fc
        elif atom_list is None or (atom_list == np.range(natom)):
            fc2 = np.zeros((natom, natom, 3, 3), dtype='double', order='C')
            for fc, indices in zip(*alm.get_fc(1, mode='all')):
                v1, v2 = indices // 3
                c1, c2 = indices % 3
                fc2[v1, v2, c1, c2] = fc
        else:  # This case would not happen.
            fc2 = np.zeros((natom, natom, 3, 3), dtype='double', order='C')
            for fc, indices in zip(*alm.get_fc(1, mode='origin')):
                v1, v2 = indices // 3
                c1, c2 = indices % 3
                fc2[v1, v2, c1, c2] = fc
            N = natom // primitive.get_number_of_atoms()
            rotations = np.array([
                np.eye(3, dtype='intc'),
            ] * N,
                                 dtype='intc',
                                 order='C')
            distribute_force_constants(fc2,
                                       p2s_map,
                                       lattice,
                                       rotations,
                                       primitive.atomic_permutations,
                                       atom_list=atom_list)
            fc2 = np.array(fc2[atom_list], dtype='double', order='C')

    if log_level:
        print("--------------------------------"
              " ALM FC2 end "
              "-------------------------------")

    return fc2
Beispiel #8
0
def run_alm(supercell,
            primitive,
            displacements,
            forces,
            maxorder,
            is_compact_fc=False,
            options=None,
            log_level=0):
    fcs = None  # This is returned.

    lattice = supercell.cell
    positions = supercell.scaled_positions
    numbers = supercell.numbers
    natom = len(numbers)
    p2s_map = primitive.p2s_map
    p2p_map = primitive.p2p_map

    alm_options = _update_options(options)
    num_elems = len(np.unique(numbers))
    if log_level:
        print("---------------------------------"
              " ALM start "
              "--------------------------------")
        print("ALM is a non-trivial force constants calculator. "
              "Please cite the paper:")
        print("T. Tadano and S. Tsuneyuki, "
              "J. Phys. Soc. Jpn. 87, 041015 (2018).")
        print("ALM is developed at https://github.com/ttadano/ALM by T. "
              "Tadano.")
    if log_level == 1:
        print("Increase log-level to watch detailed ALM log.")

    if 'norder' in alm_options:
        _maxorder = alm_options['norder']
    elif 'maxorder' in alm_options:
        _maxorder = alm_options['maxorder']
    else:
        _maxorder = maxorder

    shape = (_maxorder, num_elems, num_elems)
    cutoff_radii = -np.ones(shape, dtype='double')
    if alm_options['cutoff'] is not None:
        if len(alm_options['cutoff']) == 1:
            cutoff_radii[:] = alm_options['cutoff'][0]
        elif np.prod(shape) == len(alm_options['cutoff']):
            cutoff_radii[:] = np.reshape(alm_options['cutoff'], shape)
        else:
            raise RuntimeError("Cutoff is not properly set.")

    _disps, _forces, df_msg = _slice_displacements_and_forces(
        displacements,
        forces,
        alm_options['ndata'],
        alm_options['nstart'],
        alm_options['nend'])

    if log_level > 1:
        print("")
        print("  ndata: %d" % len(displacements))
        for key, val in alm_options.items():
            if val is not None:
                print("  %s: %s" % (key, val))
        print("")
        print(" " + "-" * 67)

    if log_level > 0:
        log_level_alm = log_level - 1
    else:
        log_level_alm = 0

    try:
        from alm import ALM, optimizer_control_data_types
    except ImportError:
        raise ImportError("ALM python module was not found.")

    with ALM(lattice, positions, numbers) as alm:
        if log_level > 0:
            if alm_options['cutoff'] is not None:
                for i in range(_maxorder):
                    if _maxorder > 1:
                        print("fc%d" % (i + 2))
                    print(("cutoff" + " %6s" * num_elems)
                          % tuple(alm.kind_names.values()))
                    for r, kn in zip(cutoff_radii[i], alm.kind_names.values()):
                        print(("   %-3s" + " %6.2f" * num_elems)
                              % ((kn, ) + tuple(r)))
            if df_msg is not None:
                print(df_msg)
        if log_level > 1:
            print("")
        sys.stdout.flush()

        alm.output_filename_prefix = alm_options['output_filename_prefix']
        alm.verbosity = log_level_alm

        alm.define(
            _maxorder,
            cutoff_radii=cutoff_radii,
            nbody=alm_options['nbody'],
            symmetrization_basis=alm_options['symmetrization_basis'])
        alm.displacements = _disps
        alm.forces = _forces

        # Mainly for elastic net (or lasso) regression
        optcontrol = {}
        for key in optimizer_control_data_types:
            if key in alm_options:
                optcontrol[key] = alm_options[key]
        if optcontrol:
            alm.optimizer_control = optcontrol
            if ('cross_validation' in optcontrol and
                optcontrol['cross_validation'] > 0):
                alm.optimize(solver=alm_options['solver'])
                optcontrol['cross_validation'] = 0
                optcontrol['l1_alpha'] = alm.cv_l1_alpha
                alm.optimizer_control = optcontrol

        alm.optimize(solver=alm_options['solver'])

        fcs = _extract_fc_from_alm(alm,
                                   natom,
                                   maxorder,
                                   is_compact_fc,
                                   p2s_map=p2s_map,
                                   p2p_map=p2p_map)

    if log_level:
        print("----------------------------------"
              " ALM end "
              "---------------------------------")

    return fcs
Beispiel #9
0
def optimize(lattice,
             positions,
             numbers,
             displacements,
             forces,
             alm_options=None,
             p2s_map=None,
             p2p_map=None,
             log_level=0):
    """Calculate force constants

    lattice : array_like
        Basis vectors. a, b, c are given as column vectors.
        shape=(3, 3), dtype='double'
    positions : array_like
        Fractional coordinates of atomic points.
        shape=(num_atoms, 3), dtype='double'
    numbers : array_like
        Atomic numbers.
        shape=(num_atoms,), dtype='intc'
    displacements : array_like
        Atomic displacement patterns in supercells in Cartesian.
        dtype='double', shape=(supercells, num_atoms, 3)
    forces : array_like
        Forces in supercells.
        dtype='double', shape=(supercells, num_atoms, 3)
    alm_options : dict, optional
        Default is None.
        List of keys
            cutoff_distance : float
            solver : str
                Either 'SimplicialLDLT' or 'dense'. Default is
                'SimplicialLDLT'.

    """

    from alm import ALM
    with ALM(lattice, positions, numbers) as alm:
        natom = len(numbers)
        alm.set_verbosity(log_level)
        nkd = len(np.unique(numbers))
        if 'cutoff_distance' not in alm_options:
            rcs = -np.ones((2, nkd, nkd), dtype='double')
        elif type(alm_options['cutoff_distance']) is float:
            rcs = np.ones((2, nkd, nkd), dtype='double')
            rcs[0] *= -1
            rcs[1] *= alm_options['cutoff_distance']
        alm.define(2, rcs)
        alm.set_displacement_and_force(displacements, forces)

        if 'solver' in alm_options:
            solver = alm_options['solver']
        else:
            solver = 'SimplicialLDLT'
        info = alm.optimize(solver=solver)
        fc2 = extract_fc2_from_alm(alm,
                                   natom,
                                   atom_list=p2s_map,
                                   p2s_map=p2s_map,
                                   p2p_map=p2p_map)
        fc3 = _extract_fc3_from_alm(alm,
                                    natom,
                                    p2s_map=p2s_map,
                                    p2p_map=p2p_map)
        return fc2, fc3