static void set_positions(Cell * trimmed_cell, const VecDBL * position, const int * mapping_table, const int * overlap_table) { int i, j, k, l, multi; for (i = 0; i < trimmed_cell->size; i++) { for (j = 0; j < 3; j++) { trimmed_cell->position[i][j] = 0; } } /* Positions of overlapped atoms are averaged. */ for (i = 0; i < position->size; i++) { j = mapping_table[i]; k = overlap_table[i]; for (l = 0; l < 3; l++) { /* boundary treatment */ /* One is at right and one is at left or vice versa. */ if (mat_Dabs(position->vec[k][l] - position->vec[i][l]) > 0.5) { if (position->vec[i][l] < position->vec[k][l]) { trimmed_cell->position[j][l] += position->vec[i][l] + 1; } else { trimmed_cell->position[j][l] += position->vec[i][l] - 1; } } else { trimmed_cell->position[j][l] += position->vec[i][l]; } } } multi = position->size / trimmed_cell->size; for (i = 0; i < trimmed_cell->size; i++) { for (j = 0; j < 3; j++) { trimmed_cell->position[i][j] /= multi; trimmed_cell->position[i][j] = mat_Dmod1(trimmed_cell->position[i][j]); } } }
/* Return NULL if failed */ static Cell * get_cell_with_smallest_lattice(SPGCONST Cell * cell, const double symprec) { int i, j; double min_lat[3][3], trans_mat[3][3], inv_lat[3][3]; Cell * smallest_cell; debug_print("get_cell_with_smallest_lattice:\n"); smallest_cell = NULL; if (!lat_smallest_lattice_vector(min_lat, cell->lattice, symprec)) { goto err; } mat_inverse_matrix_d3(inv_lat, min_lat, 0); mat_multiply_matrix_d3(trans_mat, inv_lat, cell->lattice); if ((smallest_cell = cel_alloc_cell(cell->size)) == NULL) { goto err; } mat_copy_matrix_d3(smallest_cell->lattice, min_lat); for (i = 0; i < cell->size; i++) { smallest_cell->types[i] = cell->types[i]; mat_multiply_matrix_vector_d3(smallest_cell->position[i], trans_mat, cell->position[i]); for (j = 0; j < 3; j++) { cell->position[i][j] = mat_Dmod1(cell->position[i][j]); } } return smallest_cell; err: return NULL; }
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; }
/* Return NULL if failed */ static VecDBL * get_lattice_translations(const int frame[3], SPGCONST double inv_tmat[3][3]) { int i, j, k, l, num_trans; VecDBL * lattice_trans; lattice_trans = NULL; if ((lattice_trans = mat_alloc_VecDBL(frame[0] * frame[1] * frame[2])) == NULL) { return NULL; } num_trans = 0; for (i = 0; i < frame[0]; i++) { for (j = 0; j < frame[1]; j++) { for (k = 0; k < frame[2]; k++) { lattice_trans->vec[num_trans][0] = i; lattice_trans->vec[num_trans][1] = j; lattice_trans->vec[num_trans][2] = k; /* t' = T^-1*t */ mat_multiply_matrix_vector_d3(lattice_trans->vec[num_trans], inv_tmat, lattice_trans->vec[num_trans]); for (l = 0; l < 3; l++) { lattice_trans->vec[num_trans][l] = mat_Dmod1(lattice_trans->vec[num_trans][l]); } num_trans++; } } } return lattice_trans; }
static Symmetry * reduce_symmetry_in_frame(const int frame[3], SPGCONST Symmetry *prim_sym, SPGCONST int t_mat[3][3], SPGCONST double lattice[3][3], const int multiplicity, const double symprec) { int i, j, k, l, num_trans, size_sym_orig; Symmetry *symmetry, *t_sym; double inv_tmat[3][3], tmp_mat[3][3], tmp_rot_d[3][3], tmp_lat_d[3][3], tmp_lat_i[3][3]; int tmp_rot_i[3][3]; VecDBL *pure_trans, *lattice_trans; mat_cast_matrix_3i_to_3d(tmp_mat, t_mat); mat_inverse_matrix_d3(inv_tmat, tmp_mat, symprec); /* transformed lattice points */ lattice_trans = mat_alloc_VecDBL(frame[0]*frame[1]*frame[2]); num_trans = 0; for (i = 0; i < frame[0]; i++) { for (j = 0; j < frame[1]; j++) { for (k = 0; k < frame[2]; k++) { lattice_trans->vec[num_trans][0] = i; lattice_trans->vec[num_trans][1] = j; lattice_trans->vec[num_trans][2] = k; mat_multiply_matrix_vector_d3(lattice_trans->vec[num_trans], inv_tmat, lattice_trans->vec[num_trans]); for (l = 0; l < 3; l++) { /* t' = T^-1*t */ lattice_trans->vec[num_trans][l] = \ mat_Dmod1(lattice_trans->vec[num_trans][l]); } num_trans++; } } } /* transformed symmetry operations of primitive cell */ t_sym = sym_alloc_symmetry(prim_sym->size); size_sym_orig = 0; for (i = 0; i < prim_sym->size; i++) { /* R' = T^-1*R*T */ mat_multiply_matrix_di3(tmp_mat, inv_tmat, prim_sym->rot[i]); mat_multiply_matrix_di3(tmp_rot_d, tmp_mat, t_mat); mat_cast_matrix_3d_to_3i(tmp_rot_i, tmp_rot_d); mat_multiply_matrix_di3(tmp_lat_i, lattice, tmp_rot_i); mat_multiply_matrix_d3(tmp_lat_d, lattice, tmp_rot_d); if (mat_check_identity_matrix_d3(tmp_lat_i, tmp_lat_d, symprec)) { mat_copy_matrix_i3(t_sym->rot[size_sym_orig], tmp_rot_i); /* t' = T^-1*t */ mat_multiply_matrix_vector_d3(t_sym->trans[size_sym_orig], inv_tmat, prim_sym->trans[i]); size_sym_orig++; } } /* reduce lattice points */ pure_trans = reduce_lattice_points(lattice, lattice_trans, symprec); if (! (pure_trans->size == multiplicity)) { symmetry = sym_alloc_symmetry(0); goto ret; } /* copy symmetry operations upon lattice points */ symmetry = sym_alloc_symmetry(pure_trans->size * size_sym_orig); for (i = 0; i < pure_trans->size; i++) { for (j = 0; j < size_sym_orig; j++) { mat_copy_matrix_i3(symmetry->rot[size_sym_orig * i + j], t_sym->rot[j]); mat_copy_vector_d3(symmetry->trans[size_sym_orig * i + j], t_sym->trans[j]); for (k = 0; k < 3; k++) { symmetry->trans[size_sym_orig * i + j][k] += pure_trans->vec[i][k]; symmetry->trans[size_sym_orig * i + j][k] = \ mat_Dmod1(symmetry->trans[size_sym_orig * i + j][k]); } } } ret: mat_free_VecDBL(lattice_trans); mat_free_VecDBL(pure_trans); sym_free_symmetry(t_sym); return symmetry; }
static Symmetry * reduce_symmetry_in_frame( const int frame[3], SPGCONST Symmetry *prim_sym, SPGCONST int t_mat[3][3], SPGCONST double lattice[3][3], const double symprec ) { int i, j, k, l, n, num_op, is_found; Symmetry *symmetry, *t_sym; double inv_mat[3][3], tmp_mat[3][3]; VecDBL *t, *lattice_trans; mat_cast_matrix_3i_to_3d( tmp_mat, t_mat ); mat_inverse_matrix_d3( inv_mat, tmp_mat, symprec ); /* transformed lattice points */ lattice_trans = mat_alloc_VecDBL( frame[0]*frame[1]*frame[2] ); n = 0; for ( i = 0; i < frame[0]; i++ ) { for ( j = 0; j < frame[1]; j++ ) { for ( k = 0; k < frame[2]; k++ ) { lattice_trans->vec[n][0] = i; lattice_trans->vec[n][1] = j; lattice_trans->vec[n][2] = k; mat_multiply_matrix_vector_d3( lattice_trans->vec[n], inv_mat, lattice_trans->vec[n] ); for ( l = 0; l < 3; l++ ) { /* t' = T^-1*t */ lattice_trans->vec[n][l] = mat_Dmod1( lattice_trans->vec[n][l] ); } n++; } } } /* transformed symmetry operations of primitive cell */ t_sym = sym_alloc_symmetry( prim_sym->size ); for ( i = 0; i < prim_sym->size; i++ ) { /* R' = T^-1*R*T */ mat_multiply_matrix_di3( tmp_mat, inv_mat, prim_sym->rot[i] ); mat_multiply_matrix_di3( tmp_mat, tmp_mat, t_mat ); mat_cast_matrix_3d_to_3i( t_sym->rot[i], tmp_mat ); /* t' = T^-1*t */ mat_multiply_matrix_vector_d3( t_sym->trans[i], inv_mat, prim_sym->trans[ i ] ); } /* reduce lattice points */ num_op = 0; t = mat_alloc_VecDBL( lattice_trans->size ); for ( i = 0; i < lattice_trans->size; i++ ) { is_found = 0; for ( j = 0; j < num_op; j++ ) { if ( cel_is_overlap( lattice_trans->vec[i], t->vec[j], lattice, symprec ) ) { is_found = 1; break; } } if ( ! is_found ) { mat_copy_vector_d3( t->vec[num_op], lattice_trans->vec[i] ); num_op++; } } /* copy symmetry operations upon lattice points */ symmetry = sym_alloc_symmetry( num_op * t_sym->size ); for ( i = 0; i < num_op; i++ ) { for ( j = 0; j < t_sym->size; j++ ) { mat_copy_matrix_i3( symmetry->rot[ t_sym->size * i + j ], t_sym->rot[j] ); mat_copy_vector_d3( symmetry->trans[ t_sym->size * i + j ], t_sym->trans[j] ); for ( k = 0; k < 3; k++ ) { symmetry->trans[ t_sym->size * i + j ][k] += t->vec[i][k]; symmetry->trans[ t_sym->size * i + j ][k] = \ mat_Dmod1( symmetry->trans[ t_sym->size * i + j ][k] ); } } } mat_free_VecDBL( t ); sym_free_symmetry( t_sym ); return symmetry; }
/* Return NULL if failed */ 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_exact_positions\n"); indep_atoms = NULL; positions = NULL; if ((indep_atoms = (int*) malloc(sizeof(int) * bravais->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return NULL; } if ((positions = mat_alloc_VecDBL(bravais->size)) == NULL) { free(indep_atoms); indep_atoms = NULL; return NULL; } 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++) { positions->vec[i][l] = mat_Dmod1(pos[l]); } 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; for (i = 0; i < bravais->size; i++) { if (wyckoffs[i] == -1) { mat_free_VecDBL(positions); positions = NULL; break; } } return positions; }
static Symmetry * get_primitive_db_symmetry(SPGCONST double t_mat[3][3], const Symmetry *conv_sym) { int i, j, num_op; double inv_mat[3][3], tmp_mat[3][3]; MatINT *r_prim; VecDBL *t_prim; Symmetry *prim_sym; r_prim = NULL; t_prim = NULL; prim_sym = NULL; if ((r_prim = mat_alloc_MatINT(conv_sym->size)) == NULL) { return NULL; } if ((t_prim = mat_alloc_VecDBL(conv_sym->size)) == NULL) { mat_free_MatINT(r_prim); r_prim = NULL; return NULL; } mat_inverse_matrix_d3(inv_mat, t_mat, 0); num_op = 0; for (i = 0; i < conv_sym->size; i++) { for (j = 0; j < i; j++) { if (mat_check_identity_matrix_i3(conv_sym->rot[i], conv_sym->rot[j])) { goto pass; } } /* R' = T*R*T^-1 */ mat_multiply_matrix_di3(tmp_mat, t_mat, conv_sym->rot[i]); mat_multiply_matrix_d3(tmp_mat, tmp_mat, inv_mat); mat_cast_matrix_3d_to_3i(r_prim->mat[ num_op ], tmp_mat); /* t' = T*t */ mat_multiply_matrix_vector_d3(t_prim->vec[num_op], t_mat, conv_sym->trans[i]); num_op++; pass: ; } if ((prim_sym = sym_alloc_symmetry(num_op)) == NULL) { goto ret; } for (i = 0; i < num_op; i++) { mat_copy_matrix_i3(prim_sym->rot[i], r_prim->mat[i]); for (j = 0; j < 3; j++) { prim_sym->trans[i][j] = mat_Dmod1(t_prim->vec[i][j]); } } ret: mat_free_MatINT(r_prim); r_prim = NULL; mat_free_VecDBL(t_prim); t_prim = NULL; return prim_sym; }
/* Return NULL if failed */ static Symmetry * get_conventional_symmetry(SPGCONST double transform_mat[3][3], const Centering centering, const Symmetry *primitive_sym) { int i, j, k, multi, size; double inv_tmat[3][3], shift[4][3]; double symmetry_rot_d3[3][3], primitive_sym_rot_d3[3][3]; Symmetry *symmetry; symmetry = NULL; size = primitive_sym->size; switch (centering) { case FACE: if ((symmetry = sym_alloc_symmetry(size * 4)) == NULL) { return NULL; } break; case R_CENTER: if ((symmetry = sym_alloc_symmetry(size * 3)) == NULL) { return NULL; } break; case BODY: case A_FACE: case B_FACE: case C_FACE: if ((symmetry = sym_alloc_symmetry(size * 2)) == NULL) { return NULL; } break; default: if ((symmetry = sym_alloc_symmetry(size)) == NULL) { return NULL; } break; } for (i = 0; i < size; i++) { mat_cast_matrix_3i_to_3d(primitive_sym_rot_d3, primitive_sym->rot[i]); /* C*S*C^-1: recover conventional cell symmetry operation */ mat_get_similar_matrix_d3(symmetry_rot_d3, primitive_sym_rot_d3, transform_mat, 0); mat_cast_matrix_3d_to_3i(symmetry->rot[i], symmetry_rot_d3); /* translation in conventional cell: C = B^-1*P */ mat_inverse_matrix_d3(inv_tmat, transform_mat, 0); mat_multiply_matrix_vector_d3(symmetry->trans[i], inv_tmat, primitive_sym->trans[i]); } multi = 1; if (centering != PRIMITIVE) { if (centering != FACE && centering != R_CENTER) { for (i = 0; i < 3; i++) { shift[0][i] = 0.5; } /* BASE */ if (centering == A_FACE) { shift[0][0] = 0; } if (centering == B_FACE) { shift[0][1] = 0; } if (centering == C_FACE) { shift[0][2] = 0; } multi = 2; } if (centering == R_CENTER) { shift[0][0] = 2. / 3; shift[0][1] = 1. / 3; shift[0][2] = 1. / 3; shift[1][0] = 1. / 3; shift[1][1] = 2. / 3; shift[1][2] = 2. / 3; multi = 3; } if (centering == FACE) { shift[0][0] = 0; shift[0][1] = 0.5; shift[0][2] = 0.5; shift[1][0] = 0.5; shift[1][1] = 0; shift[1][2] = 0.5; shift[2][0] = 0.5; shift[2][1] = 0.5; shift[2][2] = 0; multi = 4; } for (i = 0; i < multi - 1; i++) { for (j = 0; j < size; j++) { mat_copy_matrix_i3(symmetry->rot[(i+1) * size + j], symmetry->rot[j]); for (k = 0; k < 3; k++) { symmetry->trans[(i+1) * size + j][k] = symmetry->trans[j][k] + shift[i][k]; } } } } for (i = 0; i < multi; i++) { for (j = 0; j < size; j++) { for (k = 0; k < 3; k++) { symmetry->trans[i * size + j][k] = mat_Dmod1(symmetry->trans[i * size + j][k]); } } } return symmetry; }