static int get_Wyckoff_notation(double position[3], SPGCONST Symmetry * conv_sym, SPGCONST double bravais_lattice[3][3], const int hall_number, const double symprec) { int i, j, k, l, at_orbit, num_sitesym, wyckoff_letter=-1; int indices_wyc[2]; int rot[3][3]; double trans[3], orbit[3]; VecDBL *pos_rot; pos_rot = mat_alloc_VecDBL(conv_sym->size); for (i = 0; i < conv_sym->size; i++) { mat_multiply_matrix_vector_id3(pos_rot->vec[i], conv_sym->rot[i], position); for (j = 0; j < 3; j++) { pos_rot->vec[i][j] += conv_sym->trans[i][j]; } } ssmdb_get_wyckoff_indices(indices_wyc, hall_number); for (i = 0; i < indices_wyc[1]; i++) { num_sitesym = ssmdb_get_coordinate(rot, trans, i + indices_wyc[0]); for (j = 0; j < pos_rot->size; j++) { at_orbit = 0; for (k = 0; k < pos_rot->size; k++) { if (cel_is_overlap(pos_rot->vec[j], pos_rot->vec[k], bravais_lattice, symprec)) { mat_multiply_matrix_vector_id3(orbit, rot, pos_rot->vec[k]); for (l = 0; l < 3; l++) { orbit[l] += trans[l]; } if (cel_is_overlap(pos_rot->vec[k], orbit, bravais_lattice, symprec)) { at_orbit++; } } } if (at_orbit == conv_sym->size / num_sitesym) { /* Database is made reversed order, e.g., gfedcba. */ /* wyckoff is set 0 1 2 3 4... for a b c d e..., respectively. */ wyckoff_letter = indices_wyc[1] - i - 1; goto end; } } } end: mat_free_VecDBL(pos_rot); return wyckoff_letter; }
/* Acta Cryst. (2002). A58, 60-65 */ static void get_exact_location(double position[3], SPGCONST Symmetry * conv_sym, SPGCONST double bravais_lattice[3][3], const double symprec) { int i, j, k, num_sum; double sum_rot[3][3]; double pos[3], sum_trans[3]; debug_print("get_exact_location\n"); num_sum = 0; for (i = 0; i < 3; i++) { sum_trans[i] = 0.0; for (j = 0; j < 3; j++) { sum_rot[i][j] = 0; } } for (i = 0; i < conv_sym->size; i++) { mat_multiply_matrix_vector_id3(pos, conv_sym->rot[i], position); for (j = 0; j < 3; j++) { pos[j] += conv_sym->trans[i][j]; } if (cel_is_overlap(pos, position, bravais_lattice, symprec)) { for (j = 0; j < 3; j++) { sum_trans[j] += conv_sym->trans[i][j] - mat_Nint(pos[j] - position[j]); for (k = 0; k < 3; k++) { sum_rot[j][k] += conv_sym->rot[i][j][k]; } } num_sum++; } } for (i = 0; i < 3; i++) { sum_trans[i] /= num_sum; for (j = 0; j < 3; j++) { sum_rot[i][j] /= num_sum; } } /* (sum_rot|sum_trans) is the special-position operator. */ /* Elements of sum_rot can be fractional values. */ mat_multiply_matrix_vector_d3(position, sum_rot, position); for (i = 0; i < 3; i++) { position[i] += sum_trans[i]; } }
/* This function is heaviest in this code. */ static VecDBL * get_translation( SPGCONST int rot[3][3], SPGCONST Cell *cell, const double symprec, const int is_identity ) { int i, j, min_atom_index, num_trans = 0; int *is_found; double origin[3]; VecDBL *tmp_trans, *trans; tmp_trans = mat_alloc_VecDBL( cell->size ); is_found = (int*) malloc( sizeof(int)*cell->size); for ( i = 0; i < cell->size; i++ ) { is_found[i] = 0; } /* Look for the atom index with least number of atoms within same type */ min_atom_index = get_index_with_least_atoms( cell ); /* Set min_atom_index as the origin to measure the distance between atoms. */ mat_multiply_matrix_vector_id3(origin, rot, cell->position[min_atom_index]); #pragma omp parallel for private( j ) for (i = 0; i < cell->size; i++) { /* test translation */ if (cell->types[i] != cell->types[min_atom_index]) { continue; } for (j = 0; j < 3; j++) { tmp_trans->vec[i][j] = cell->position[i][j] - origin[j]; } if ( is_overlap_all_atoms( tmp_trans->vec[i], rot, cell, symprec, is_identity ) ) { is_found[i] = 1; } } for ( i = 0; i < cell->size; i++ ) { num_trans += is_found[i]; } trans = mat_alloc_VecDBL( num_trans ); num_trans = 0; for ( i = 0; i < cell->size; i++ ) { if ( is_found[i] ) { mat_copy_vector_d3( trans->vec[num_trans], tmp_trans->vec[i] ); num_trans++; } } mat_free_VecDBL( tmp_trans ); free( is_found ); is_found = NULL; return trans; }
static MatINT *get_point_group_reciprocal_with_q(const MatINT * rot_reciprocal, const double symprec, const int num_q, SPGCONST double qpoints[][3]) { int i, j, k, l, is_all_ok, num_rot; int *ir_rot; double q_rot[3], diff[3]; MatINT * rot_reciprocal_q; is_all_ok = 0; num_rot = 0; ir_rot = (int*)malloc(sizeof(int) * rot_reciprocal->size); for (i = 0; i < rot_reciprocal->size; i++) { ir_rot[i] = -1; } for (i = 0; i < rot_reciprocal->size; i++) { for (j = 0; j < num_q; j++) { is_all_ok = 0; mat_multiply_matrix_vector_id3(q_rot, rot_reciprocal->mat[i], qpoints[j]); for (k = 0; k < num_q; k++) { for (l = 0; l < 3; l++) { diff[l] = q_rot[l] - qpoints[k][l]; diff[l] -= mat_Nint(diff[l]); } if (mat_Dabs(diff[0]) < symprec && mat_Dabs(diff[1]) < symprec && mat_Dabs(diff[2]) < symprec) { is_all_ok = 1; break; } } if (! is_all_ok) { break; } } if (is_all_ok) { ir_rot[num_rot] = i; num_rot++; } } rot_reciprocal_q = mat_alloc_MatINT(num_rot); for (i = 0; i < num_rot; i++) { mat_copy_matrix_i3(rot_reciprocal_q->mat[i], rot_reciprocal->mat[ir_rot[i]]); } free(ir_rot); return rot_reciprocal_q; }
/* Return 0 if failed */ static int set_equivalent_atoms(int * equiv_atoms, SPGCONST Symmetry *symmetry, SPGCONST Cell * cell, const double symprec) { int i, j, k, is_found; double pos[3]; int *mapping_table; mapping_table = NULL; if ((mapping_table = get_mapping_table(symmetry, cell, symprec)) == NULL) { return 0; } for (i = 0; i < cell->size; i++) { if (mapping_table[i] != i) { continue; } is_found = 0; for (j = 0; j < symmetry->size; j++) { mat_multiply_matrix_vector_id3(pos, symmetry->rot[j], cell->position[i]); for (k = 0; k < 3; k++) { pos[k] += symmetry->trans[j][k]; } for (k = 0; k < cell->size; k++) { if (cel_is_overlap(pos, cell->position[k], cell->lattice, symprec)) { if (mapping_table[k] < i) { equiv_atoms[i] = equiv_atoms[mapping_table[k]]; is_found = 1; break; } } } if (is_found) { break; } } if (!is_found) { equiv_atoms[i] = i; } } for (i = 0; i < cell->size; i++) { if (mapping_table[i] == i) { continue; } equiv_atoms[i] = equiv_atoms[mapping_table[i]]; } free(mapping_table); mapping_table = NULL; return 1; }
static int is_overlap_all_atoms(const double trans[3], SPGCONST int rot[3][3], SPGCONST Cell * cell, const double symprec, const int is_identity) { int i, j, k, is_found; double symprec2; double pos_rot[3], d[3]; symprec2 = symprec*symprec; for (i = 0; i < cell->size; i++) { if (is_identity) { /* Identity matrix is treated as special for speed. */ for (j = 0; j < 3; j++) { pos_rot[j] = cell->position[i][j] + trans[j]; } } else { mat_multiply_matrix_vector_id3(pos_rot, rot, cell->position[i]); for (j = 0; j < 3; j++) { pos_rot[j] += trans[j]; } } is_found = 0; for (j = 0; j < cell->size; j++) { if (cell->types[i] == cell->types[j]) { /* here cel_is_overlap can be used, but for the tuning */ /* purpose, write it again */ for (k = 0; k < 3; k++) { d[k] = pos_rot[k] - cell->position[j][k]; d[k] -= mat_Nint(d[k]); } mat_multiply_matrix_vector_d3(d, cell->lattice, d); if (d[0]*d[0]+d[1]*d[1]+d[2]*d[2] < symprec2) { is_found = 1; break; } } } if (! is_found) { goto not_found; } } return 1; /* found */ not_found: return 0; }
static PointSymmetry get_point_group_reciprocal_with_q(SPGCONST PointSymmetry * pointgroup, const double symprec, const int num_q, SPGCONST double qpoints[][3]) { int i, j, k, l, is_all_ok=0, num_ptq = 0; double q_rot[3], diff[3]; PointSymmetry pointgroup_q; for (i = 0; i < pointgroup->size; i++) { for (j = 0; j < num_q; j++) { is_all_ok = 0; mat_multiply_matrix_vector_id3(q_rot, pointgroup->rot[i], qpoints[j]); for (k = 0; k < num_q; k++) { for (l = 0; l < 3; l++) { diff[l] = q_rot[l] - qpoints[k][l]; diff[l] -= mat_Nint(diff[l]); } if (mat_Dabs(diff[0]) < symprec && mat_Dabs(diff[1]) < symprec && mat_Dabs(diff[2]) < symprec) { is_all_ok = 1; break; } } if (! is_all_ok) { break; } } if (is_all_ok) { mat_copy_matrix_i3(pointgroup_q.rot[num_ptq], pointgroup->rot[i]); num_ptq++; } } pointgroup_q.size = num_ptq; return pointgroup_q; }
static void set_translation_with_origin_shift(Symmetry *conv_sym, const double origin_shift[3]) { int i, j; double tmp_vec[3]; int tmp_mat[3][3]; /* t' = t - (R-E)w, w is the origin shift */ for (i = 0; i < conv_sym->size; i++) { mat_copy_matrix_i3(tmp_mat, conv_sym->rot[i]); tmp_mat[0][0]--; tmp_mat[1][1]--; tmp_mat[2][2]--; mat_multiply_matrix_vector_id3(tmp_vec, tmp_mat, origin_shift); for (j = 0; j < 3; j++) { conv_sym->trans[i][j] -= tmp_vec[j]; } } }
static int search_equivalent_atom(const int atom_index, SPGCONST Cell * cell, const Symmetry *symmetry, const double symprec) { int i, j; double pos_rot[3]; for (i = 0; i < symmetry->size; i++) { mat_multiply_matrix_vector_id3(pos_rot, symmetry->rot[i], cell->position[atom_index]); for (j = 0; j < 3; j++) { pos_rot[j] += symmetry->trans[i][j]; } for (j = 0; j < atom_index; j++) { if (cel_is_overlap(cell->position[j], pos_rot, cell->lattice, symprec)) { return j; } } } return atom_index; }
static int set_equivalent_atom(VecDBL *positions, int * equiv_atoms, const int i, const int num_indep_atoms, const int *indep_atoms, const Cell * conv_prim, const Symmetry * conv_sym, const double symprec) { int j, k, l; double pos[3]; for (j = 0; j < num_indep_atoms; j++) { for (k = 0; k < conv_sym->size; k++) { mat_multiply_matrix_vector_id3(pos, conv_sym->rot[k], positions->vec[indep_atoms[j]]); for (l = 0; l < 3; l++) { pos[l] += conv_sym->trans[k][l]; } if (cel_is_overlap_with_same_type(pos, conv_prim->position[i], conv_prim->types[indep_atoms[j]], conv_prim->types[i], conv_prim->lattice, symprec)) { for (l = 0; l < 3; l++) { positions->vec[i][l] = mat_Dmod1(pos[l]); } equiv_atoms[i] = indep_atoms[j]; return 1; } } } return 0; }
static VecDBL * get_exact_positions(int * wyckoffs, int * equiv_atoms, SPGCONST Cell * bravais, SPGCONST Symmetry * conv_sym, const int hall_number, const double symprec) { int i, j, k, l, num_indep_atoms; double pos[3]; int *indep_atoms; VecDBL *positions; debug_print("get_symmetrized_positions\n"); indep_atoms = (int*) malloc(sizeof(int) * bravais->size); positions = mat_alloc_VecDBL(bravais->size); num_indep_atoms = 0; for (i = 0; i < bravais->size; i++) { /* Check if atom_i overlap to an atom already set at the exact position. */ for (j = 0; j < num_indep_atoms; j++) { for (k = 0; k < conv_sym->size; k++) { mat_multiply_matrix_vector_id3(pos, conv_sym->rot[k], positions->vec[indep_atoms[j]]); for (l = 0; l < 3; l++) { pos[l] += conv_sym->trans[k][l]; } if (cel_is_overlap(pos, bravais->position[i], bravais->lattice, symprec)) { /* Equivalent atom was found. */ for (l = 0; l < 3; l++) { pos[l] -= mat_Nint(pos[l]); } mat_copy_vector_d3(positions->vec[i], pos); wyckoffs[i] = wyckoffs[indep_atoms[j]]; equiv_atoms[i] = indep_atoms[j]; goto escape; } } } /* No equivalent atom was found. */ indep_atoms[num_indep_atoms] = i; num_indep_atoms++; mat_copy_vector_d3(positions->vec[i], bravais->position[i]); get_exact_location(positions->vec[i], conv_sym, bravais->lattice, symprec); wyckoffs[i] = get_Wyckoff_notation(positions->vec[i], conv_sym, bravais->lattice, hall_number, symprec); equiv_atoms[i] = i; escape: ; } free(indep_atoms); indep_atoms = NULL; return positions; }
/* This function is heaviest in this code. */ static VecDBL * get_translation(SPGCONST int rot[3][3], SPGCONST Cell *cell, const double symprec, const int is_identity) { int i, j, min_atom_index, num_trans = 0; int *is_found; double origin[3]; VecDBL *trans; #ifdef _OPENMP int num_min_type_atoms; int *min_type_atoms; double vec[3]; #endif is_found = (int*) malloc(sizeof(int)*cell->size); for (i = 0; i < cell->size; i++) { is_found[i] = 0; } /* Look for the atom index with least number of atoms within same type */ min_atom_index = get_index_with_least_atoms(cell); /* Set min_atom_index as the origin to measure the distance between atoms. */ mat_multiply_matrix_vector_id3(origin, rot, cell->position[min_atom_index]); #ifdef _OPENMP if (cell->size < NUM_ATOMS_CRITERION_FOR_OPENMP) { search_translation_part(is_found, cell, rot, min_atom_index, origin, symprec, is_identity); } else { /* Collect indices of atoms with the type where the minimum number */ /* of atoms belong. */ min_type_atoms = (int*) malloc(sizeof(int)*cell->size); num_min_type_atoms = 0; for (i = 0; i < cell->size; i++) { if (cell->types[i] == cell->types[min_atom_index]) { min_type_atoms[num_min_type_atoms] = i; num_min_type_atoms++; } } #pragma omp parallel for private(j, vec) for (i = 0; i < num_min_type_atoms; i++) { for (j = 0; j < 3; j++) { vec[j] = cell->position[min_type_atoms[i]][j] - origin[j]; } if (is_overlap_all_atoms(vec, rot, cell, symprec, is_identity)) { is_found[min_type_atoms[i]] = 1; } } free(min_type_atoms); } #else search_translation_part(is_found, cell, rot, min_atom_index, origin, symprec, is_identity); #endif for (i = 0; i < cell->size; i++) { num_trans += is_found[i]; } trans = mat_alloc_VecDBL(num_trans); num_trans = 0; for (i = 0; i < cell->size; i++) { if (is_found[i]) { for (j = 0; j < 3; j++) { trans->vec[num_trans][j] = cell->position[i][j] - origin[j]; } num_trans++; } } free(is_found); is_found = NULL; return trans; }
/* Return NULL if failed */ static VecDBL * get_translation(SPGCONST int rot[3][3], SPGCONST Cell *cell, const double symprec, const int is_identity) { int i, j, k, min_atom_index, num_trans; int *is_found; double origin[3]; VecDBL *trans; debug_print("get_translation (tolerance = %f):\n", symprec); num_trans = 0; is_found = NULL; trans = NULL; #ifdef _OPENMP int num_min_type_atoms; int *min_type_atoms; double vec[3]; min_type_atoms = NULL; #endif if ((is_found = (int*) malloc(sizeof(int)*cell->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return NULL; } for (i = 0; i < cell->size; i++) { is_found[i] = 0; } /* Look for the atom index with least number of atoms within same type */ min_atom_index = get_index_with_least_atoms(cell); if (min_atom_index == -1) { debug_print("spglib: get_index_with_least_atoms failed.\n"); goto ret; } /* Set min_atom_index as the origin to measure the distance between atoms. */ mat_multiply_matrix_vector_id3(origin, rot, cell->position[min_atom_index]); #ifdef _OPENMP if (cell->size < NUM_ATOMS_CRITERION_FOR_OPENMP) { num_trans = search_translation_part(is_found, cell, rot, min_atom_index, origin, symprec, is_identity); if (num_trans == 0) { goto ret; } } else { /* Collect indices of atoms with the type where the minimum number */ /* of atoms belong. */ if ((min_type_atoms = (int*) malloc(sizeof(int)*cell->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); goto ret; } num_min_type_atoms = 0; for (i = 0; i < cell->size; i++) { if (cell->types[i] == cell->types[min_atom_index]) { min_type_atoms[num_min_type_atoms] = i; num_min_type_atoms++; } } #pragma omp parallel for private(j, vec) for (i = 0; i < num_min_type_atoms; i++) { for (j = 0; j < 3; j++) { vec[j] = cell->position[min_type_atoms[i]][j] - origin[j]; } if (is_overlap_all_atoms(vec, rot, cell, symprec, is_identity)) { is_found[min_type_atoms[i]] = 1; } } free(min_type_atoms); min_type_atoms = NULL; for (i = 0; i < cell->size; i++) { num_trans += is_found[i]; } } #else num_trans = search_translation_part(is_found, cell, rot, min_atom_index, origin, symprec, is_identity); if (num_trans == 0) { goto ret; } #endif if ((trans = mat_alloc_VecDBL(num_trans)) == NULL) { goto ret; } k = 0; for (i = 0; i < cell->size; i++) { if (is_found[i]) { for (j = 0; j < 3; j++) { trans->vec[k][j] = cell->position[i][j] - origin[j]; } k++; } } ret: free(is_found); is_found = NULL; return trans; }
static int get_ir_kpoints(int map[], SPGCONST double kpoints[][3], const int num_kpoint, SPGCONST PointSymmetry * point_symmetry, const double symprec) { int i, j, k, l, num_ir_kpoint = 0, is_found; int *ir_map; double kpt_rot[3], diff[3]; ir_map = (int*)malloc(num_kpoint*sizeof(int)); for (i = 0; i < num_kpoint; i++) { map[i] = i; is_found = 1; for (j = 0; j < point_symmetry->size; j++) { mat_multiply_matrix_vector_id3(kpt_rot, point_symmetry->rot[j], kpoints[i]); for (k = 0; k < 3; k++) { diff[k] = kpt_rot[k] - kpoints[i][k]; diff[k] = diff[k] - mat_Nint(diff[k]); } if (mat_Dabs(diff[0]) < symprec && mat_Dabs(diff[1]) < symprec && mat_Dabs(diff[2]) < symprec) { continue; } for (k = 0; k < num_ir_kpoint; k++) { mat_multiply_matrix_vector_id3(kpt_rot, point_symmetry->rot[j], kpoints[i]); for (l = 0; l < 3; l++) { diff[l] = kpt_rot[l] - kpoints[ir_map[k]][l]; diff[l] = diff[l] - mat_Nint(diff[l]); } if (mat_Dabs(diff[0]) < symprec && mat_Dabs(diff[1]) < symprec && mat_Dabs(diff[2]) < symprec) { is_found = 0; map[i] = ir_map[k]; break; } } if (! is_found) break; } if (is_found) { ir_map[num_ir_kpoint] = i; num_ir_kpoint++; } } free(ir_map); ir_map = NULL; return num_ir_kpoint; }
static Symmetry * get_collinear_operations(SPGCONST Symmetry *sym_nonspin, SPGCONST Cell *cell, const double spins[], const double symprec) { Symmetry *symmetry; int i, j, k, sign, is_found, num_sym; double pos[3]; MatINT * rot; VecDBL * trans; rot = mat_alloc_MatINT(sym_nonspin->size); trans = mat_alloc_VecDBL(sym_nonspin->size); num_sym = 0; for (i = 0; i < sym_nonspin->size; i++) { sign = 0; /* Set sign as undetermined */ is_found = 1; for (j = 0; j < cell->size; j++) { mat_multiply_matrix_vector_id3(pos, sym_nonspin->rot[i], cell->position[j]); for (k = 0; k < 3; k++) { pos[k] += sym_nonspin->trans[i][k]; } for (k = 0; k < cell->size; k++) { if (cel_is_overlap(cell->position[k], pos, cell->lattice, symprec)) { if (sign == 0) { if (mat_Dabs(spins[j] - spins[k]) < symprec) { sign = 1; break; } if (mat_Dabs(spins[j] + spins[k]) < symprec) { sign = -1; break; } is_found = 0; break; } else { if (mat_Dabs(spins[j] - spins[k] * sign) < symprec) { break; } else { is_found = 0; break; } } } } if (! is_found) { break; } } if (is_found) { mat_copy_matrix_i3(rot->mat[num_sym], sym_nonspin->rot[i]); mat_copy_vector_d3(trans->vec[num_sym], sym_nonspin->trans[i]); num_sym++; } } symmetry = sym_alloc_symmetry(num_sym); for (i = 0; i < num_sym; i++) { mat_copy_matrix_i3(symmetry->rot[i], rot->mat[ i ]); mat_copy_vector_d3(symmetry->trans[i], trans->vec[ i ]); } mat_free_MatINT(rot); mat_free_VecDBL(trans); return symmetry; }
/* Acta Cryst. (2002). A58, 60-65 */ static int set_exact_location(double position[3], const Symmetry * conv_sym, SPGCONST double bravais_lattice[3][3], const double symprec) { int i, j, k, num_sum, multi, num_pure_trans; double sum_rot[3][3]; double pos[3], sum_trans[3]; debug_print("get_exact_location\n"); num_sum = 0; for (i = 0; i < 3; i++) { sum_trans[i] = 0.0; for (j = 0; j < 3; j++) { sum_rot[i][j] = 0; } } num_pure_trans = 0; for (i = 0; i < conv_sym->size; i++) { if (mat_check_identity_matrix_i3(identity, conv_sym->rot[i])) { num_pure_trans++; for (j = 0; j < 3; j++) { pos[j] = position[j]; } } else { mat_multiply_matrix_vector_id3(pos, conv_sym->rot[i], position); } for (j = 0; j < 3; j++) { pos[j] += conv_sym->trans[i][j]; } if (cel_is_overlap(pos, position, bravais_lattice, symprec)) { for (j = 0; j < 3; j++) { for (k = 0; k < 3; k++) { sum_rot[j][k] += conv_sym->rot[i][j][k]; } sum_trans[j] += conv_sym->trans[i][j] - mat_Nint(pos[j] - position[j]); } num_sum++; } } for (i = 0; i < 3; i++) { sum_trans[i] /= num_sum; for (j = 0; j < 3; j++) { sum_rot[i][j] /= num_sum; } } /* (sum_rot|sum_trans) is the special-position operator. */ /* Elements of sum_rot can be fractional values. */ mat_multiply_matrix_vector_d3(position, sum_rot, position); for (i = 0; i < 3; i++) { position[i] += sum_trans[i]; } multi = conv_sym->size / num_pure_trans / num_sum; if (multi * num_sum * num_pure_trans == conv_sym->size) { return multi; } else { return 0; } }