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
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
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
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
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
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
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
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
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