static int get_grid_point_double_mesh(const int address_double[3], const int mesh[3]) { int i, address[3]; for (i = 0; i < 3; i++) { if (address_double[i] % 2 == 0) { address[i] = address_double[i] / 2; } else { address[i] = (address_double[i] - 1) / 2; } } mat_modulo_i3(address, mesh); return get_grid_point_single_mesh(address, mesh); }
static int get_ir_reciprocal_mesh(int grid_address[][3], int map[], const int mesh[3], const int is_shift[3], const MatINT *rot_reciprocal) { /* In the following loop, mesh is doubled. */ /* Even and odd mesh numbers correspond to */ /* is_shift[i] are 0 or 1, respectively. */ /* is_shift = [0,0,0] gives Gamma center mesh. */ /* grid: reducible grid points */ /* map: the mapping from each point to ir-point. */ int i, j, k, l, grid_point, grid_point_rot, num_ir = 0; int address[3], address_double[3], address_double_rot[3]; /* "-1" means the element is not touched yet. */ for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) { map[i] = -1; } #ifndef GRID_ORDER_XYZ for (i = 0; i < mesh[2]; i++) { for (j = 0; j < mesh[1]; j++) { for (k = 0; k < mesh[0]; k++) { address[0] = k; address[1] = j; address[2] = i; #else for (i = 0; i < mesh[0]; i++) { for (j = 0; j < mesh[1]; j++) { for (k = 0; k < mesh[2]; k++) { address[0] = i; address[1] = j; address[2] = k; #endif for (l = 0; l < 3; l++) { address_double[l] = address[l] * 2 + is_shift[l]; } grid_point = get_grid_point_double_mesh(address_double, mesh); reduce_grid_address(grid_address[grid_point], address, mesh); for (l = 0; l < rot_reciprocal->size; l++) { mat_multiply_matrix_vector_i3(address_double_rot, rot_reciprocal->mat[l], address_double); grid_point_rot = get_grid_point_double_mesh(address_double_rot, mesh); if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */ if (map[grid_point_rot] > -1) { map[grid_point] = map[grid_point_rot]; break; } } } if (map[grid_point] == -1) { map[grid_point] = grid_point; num_ir++; } } } } return num_ir; } static int get_ir_reciprocal_mesh_openmp(int grid_address[][3], int map[], const int mesh[3], const int is_shift[3], const MatINT * rot_reciprocal) { int i, j, k, l, grid_point, grid_point_rot, num_ir; int address[3], address_double[3], address_double_rot[3]; #ifndef GRID_ORDER_XYZ #pragma omp parallel for private(j, k, l, grid_point, grid_point_rot, address_double, address_double_rot) for (i = 0; i < mesh[2]; i++) { for (j = 0; j < mesh[1]; j++) { for (k = 0; k < mesh[0]; k++) { address[0] = k; address[1] = j; address[2] = i; #else #pragma omp parallel for private(j, k, l, grid_point, grid_point_rot, address_double, address_double_rot) for (i = 0; i < mesh[0]; i++) { for (j = 0; j < mesh[1]; j++) { for (k = 0; k < mesh[2]; k++) { address[0] = i; address[1] = j; address[2] = k; #endif for (l = 0; l < 3; l++) { address_double[l] = address[l] * 2 + is_shift[l]; } grid_point = get_grid_point_double_mesh(address_double, mesh); map[grid_point] = grid_point; reduce_grid_address(grid_address[grid_point], address, mesh); for (l = 0; l < rot_reciprocal->size; l++) { mat_multiply_matrix_vector_i3(address_double_rot, rot_reciprocal->mat[l], address_double); grid_point_rot = get_grid_point_double_mesh(address_double_rot, mesh); if (grid_point_rot > -1) { /* Invalid if even --> odd or odd --> even */ if (grid_point_rot < map[grid_point]) { map[grid_point] = grid_point_rot; } } } } } } num_ir = 0; #pragma omp parallel for reduction(+:num_ir) for (i = 0; i < mesh[0] * mesh[1] * mesh[2]; i++) { if (map[i] == i) { num_ir++; } } return num_ir; } /* Relocate grid addresses to first Brillouin zone */ /* bz_grid_address[prod(mesh + 1)][3] */ /* bz_map[prod(mesh * 2)] */ static int relocate_BZ_grid_address(int bz_grid_address[][3], int bz_map[], SPGCONST int grid_address[][3], const int mesh[3], SPGCONST double rec_lattice[3][3], const int is_shift[3]) { double tolerance, min_distance; double q_vector[3], distance[KPT_NUM_BZ_SEARCH_SPACE]; int bzmesh[3], bz_address_double[3]; int i, j, k, min_index, boundary_num_gp, total_num_gp, bzgp, gp; tolerance = get_tolerance_for_BZ_reduction(rec_lattice, mesh); for (i = 0; i < 3; i++) { bzmesh[i] = mesh[i] * 2; } for (i = 0; i < bzmesh[0] * bzmesh[1] * bzmesh[2]; i++) { bz_map[i] = -1; } boundary_num_gp = 0; total_num_gp = mesh[0] * mesh[1] * mesh[2]; for (i = 0; i < total_num_gp; i++) { for (j = 0; j < KPT_NUM_BZ_SEARCH_SPACE; j++) { for (k = 0; k < 3; k++) { q_vector[k] = ((grid_address[i][k] + kpt_bz_search_space[j][k] * mesh[k]) * 2 + is_shift[k]) / ((double)mesh[k]) / 2; } mat_multiply_matrix_vector_d3(q_vector, rec_lattice, q_vector); distance[j] = mat_norm_squared_d3(q_vector); } min_distance = distance[0]; min_index = 0; for (j = 1; j < KPT_NUM_BZ_SEARCH_SPACE; j++) { if (distance[j] < min_distance) { min_distance = distance[j]; min_index = j; } } for (j = 0; j < KPT_NUM_BZ_SEARCH_SPACE; j++) { if (distance[j] < min_distance + tolerance) { if (j == min_index) { gp = i; } else { gp = boundary_num_gp + total_num_gp; } for (k = 0; k < 3; k++) { bz_grid_address[gp][k] = grid_address[i][k] + kpt_bz_search_space[j][k] * mesh[k]; bz_address_double[k] = bz_grid_address[gp][k] * 2 + is_shift[k]; } bzgp = get_grid_point_double_mesh(bz_address_double, bzmesh); bz_map[bzgp] = gp; if (j != min_index) { boundary_num_gp++; } } } } return boundary_num_gp + total_num_gp; } static double get_tolerance_for_BZ_reduction(SPGCONST double rec_lattice[3][3], const int mesh[3]) { int i, j; double tolerance; double length[3]; for (i = 0; i < 3; i++) { length[i] = 0; for (j = 0; j < 3; j++) { length[i] += rec_lattice[j][i] * rec_lattice[j][i]; } length[i] /= mesh[i] * mesh[i]; } tolerance = length[0]; for (i = 1; i < 3; i++) { if (tolerance < length[i]) { tolerance = length[i]; } } tolerance *= 0.01; return tolerance; } static int get_grid_point_double_mesh(const int address_double[3], const int mesh[3]) { int i, address[3]; for (i = 0; i < 3; i++) { if (address_double[i] % 2 == 0) { address[i] = address_double[i] / 2; } else { address[i] = (address_double[i] - 1) / 2; } } mat_modulo_i3(address, mesh); return get_grid_point_single_mesh(address, mesh); } static int get_grid_point_single_mesh(const int address[3], const int mesh[3]) { #ifndef GRID_ORDER_XYZ return address[2] * mesh[0] * mesh[1] + address[1] * mesh[0] + address[0]; #else return address[0] * mesh[1] * mesh[2] + address[1] * mesh[2] + address[2]; #endif } static void reduce_grid_address(int reduced_address[3], const int address[3], const int mesh[3]) { int i; for (i = 0; i < 3; i++) { #ifndef GRID_BOUNDARY_AS_NEGATIVE reduced_address[i] = address[i] - mesh[i] * (address[i] > mesh[i] / 2); #else reduced_address[i] = address[i] - mesh[i] * (address[i] >= mesh[i] / 2); #endif } }