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], metric_orig[3][3]; PointSymmetry lattice_sym; debug_print("get_lattice_symmetry:\n"); if (! lat_smallest_lattice_vector(min_lattice, cell->lattice, symprec)) { goto err; } mat_get_metric(metric_orig, 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 (is_identity_metric(metric, metric_orig, 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 * get_primitive_db_symmetry(SPGCONST double t_mat[3][3], const Symmetry *conv_sym, const double symprec) { 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 = mat_alloc_MatINT(conv_sym->size); t_prim = mat_alloc_VecDBL(conv_sym->size); mat_inverse_matrix_d3(inv_mat, t_mat, symprec); 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: ; } prim_sym = sym_alloc_symmetry(num_op); 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] = t_prim->vec[i][j] - mat_Nint(t_prim->vec[i][j]); } } mat_free_MatINT(r_prim); mat_free_VecDBL(t_prim); return prim_sym; }
static PointSymmetry get_lattice_symmetry(SPGCONST double cell_lattice[3][3], const double symprec, const double angle_symprec) { int i, j, k, attempt, num_sym; double angle_tol; int axes[3][3]; double lattice[3][3], min_lattice[3][3]; double metric[3][3], metric_orig[3][3]; PointSymmetry lattice_sym; debug_print("get_lattice_symmetry:\n"); lattice_sym.size = 0; if (! del_delaunay_reduce(min_lattice, cell_lattice, symprec)) { goto err; } mat_get_metric(metric_orig, min_lattice); angle_tol = angle_symprec; for (attempt = 0; attempt < 100; attempt++) { 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 (is_identity_metric(metric, metric_orig, symprec, angle_tol)) { if (num_sym > 47) { angle_tol *= ANGLE_REDUCE_RATE; warning_print("spglib: Too many lattice symmetries was found.\n"); warning_print(" Reduce angle tolerance to %f", angle_tol); warning_print(" (line %d, %s).\n", __LINE__, __FILE__); goto next_attempt; } mat_copy_matrix_i3(lattice_sym.rot[num_sym], axes); num_sym++; } } } } if (num_sym < 49 || angle_tol < 0) { lattice_sym.size = num_sym; return transform_pointsymmetry(&lattice_sym, cell_lattice, min_lattice); } next_attempt: ; } err: debug_print("get_lattice_symmetry failed.\n"); 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; }
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 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; }
/* Return 0 if failed */ static int search_hall_number(double origin_shift[3], double conv_lattice[3][3], const int candidates[], const int num_candidates, SPGCONST double primitive_lattice[3][3], SPGCONST Symmetry * symmetry, const double symprec) { int i, hall_number; Centering centering; Pointgroup pointgroup; Symmetry * conv_symmetry; int int_transform_mat[3][3]; double correction_mat[3][3], transform_mat[3][3]; debug_print("search_hall_number:\n"); hall_number = 0; conv_symmetry = NULL; pointgroup = ptg_get_transformation_matrix(int_transform_mat, symmetry->rot, symmetry->size); if (pointgroup.number == 0) { goto err; } mat_multiply_matrix_di3(conv_lattice, primitive_lattice, int_transform_mat); if (pointgroup.laue == LAUE1) { if (! change_basis_tricli(int_transform_mat, conv_lattice, primitive_lattice, symprec)) { goto err; } } if (pointgroup.laue == LAUE2M) { if (! change_basis_monocli(int_transform_mat, conv_lattice, primitive_lattice, symprec)) { goto err; } } if ((centering = get_centering(correction_mat, int_transform_mat, pointgroup.laue)) == CENTERING_ERROR) { goto err; } mat_multiply_matrix_id3(transform_mat, int_transform_mat, correction_mat); mat_multiply_matrix_d3(conv_lattice, primitive_lattice, transform_mat); if ((conv_symmetry = get_initial_conventional_symmetry(centering, transform_mat, symmetry)) == NULL) { goto err; } for (i = 0; i < num_candidates; i++) { if (match_hall_symbol_db(origin_shift, conv_lattice, /* <-- modified only matched */ candidates[i], pointgroup.number, pointgroup.holohedry, centering, conv_symmetry, symprec)) { hall_number = candidates[i]; break; } } sym_free_symmetry(conv_symmetry); conv_symmetry = NULL; return hall_number; err: return 0; }