static PointSymmetry get_lattice_symmetry( SPGCONST Cell *cell, const double symprec ) { int i, j, k, num_sym; int axes[3][3]; double lattice[3][3], min_lattice[3][3]; double metric[3][3], cell_metric[3][3]; PointSymmetry lattice_sym; if ( ! lat_smallest_lattice_vector( min_lattice, cell->lattice, symprec ) ) { goto err; } mat_get_metric( cell_metric, min_lattice ); num_sym = 0; for ( i = 0; i < 26; i++ ) { for ( j = 0; j < 26; j++ ) { for ( k = 0; k < 26; k++ ) { set_axes( axes, i, j, k ); if ( ! ( ( mat_get_determinant_i3( axes ) == 1 ) || ( mat_get_determinant_i3( axes ) == -1 ) ) ) { continue; } mat_multiply_matrix_di3( lattice, min_lattice, axes ); mat_get_metric( metric, lattice ); if ( mat_check_identity_matrix_d3( metric, cell_metric, symprec ) ) { mat_copy_matrix_i3( lattice_sym.rot[num_sym], axes ); num_sym++; } if ( num_sym > 48 ) { warning_print("spglib: Too many lattice symmetries was found.\n"); warning_print(" Tolerance may be too large "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto err; } } } } lattice_sym.size = num_sym; return transform_pointsymmetry( &lattice_sym, cell->lattice, min_lattice ); err: lattice_sym.size = 0; return lattice_sym; }
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; }
/* Return NULL if failed */ static Symmetry * get_symmetry_in_original_cell(SPGCONST int t_mat[3][3], SPGCONST double inv_tmat[3][3], SPGCONST double lattice[3][3], SPGCONST Symmetry *prim_sym, const double symprec) { int i, size_sym_orig; double tmp_rot_d[3][3], tmp_lat_d[3][3], tmp_lat_i[3][3], tmp_mat[3][3]; int tmp_rot_i[3][3]; Symmetry *t_sym, *t_red_sym; t_sym = NULL; t_red_sym = NULL; if ((t_sym = sym_alloc_symmetry(prim_sym->size)) == NULL) { return NULL; } /* transform symmetry operations of primitive cell to those of original */ 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); /* In spglib, symmetry of supercell is defined by the set of symmetry */ /* operations that are searched among supercell lattice point group */ /* operations. The supercell lattice may be made by breaking the */ /* unit cell lattice symmetry. In this case, a part of symmetry */ /* operations is discarded. */ 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++; } } /* Broken symmetry due to supercell multiplicity */ if (size_sym_orig != prim_sym->size) { if ((t_red_sym = sym_alloc_symmetry(size_sym_orig)) == NULL) { sym_free_symmetry(t_sym); t_sym = NULL; return NULL; } for (i = 0; i < size_sym_orig; i++) { mat_copy_matrix_i3(t_red_sym->rot[i], t_sym->rot[i]); mat_copy_vector_d3(t_red_sym->trans[i], t_sym->trans[i]); } sym_free_symmetry(t_sym); t_sym = NULL; t_sym = t_red_sym; t_red_sym = NULL; } return t_sym; }