static Symmetry * recover_operations_original(SPGCONST Symmetry *symmetry, const VecDBL * pure_trans, SPGCONST Cell *cell, SPGCONST Cell *primitive) { int i, j, k, multi; double inv_prim_lat[3][3], drot[3][3], trans_mat[3][3], trans_mat_inv[3][3]; Symmetry *symmetry_orig, *sym_tmp; debug_print("recover_operations_original:\n"); multi = pure_trans->size; sym_tmp = sym_alloc_symmetry(symmetry->size); symmetry_orig = sym_alloc_symmetry(symmetry->size * multi); mat_inverse_matrix_d3(inv_prim_lat, primitive->lattice, 0); mat_multiply_matrix_d3(trans_mat, inv_prim_lat, cell->lattice); mat_inverse_matrix_d3(trans_mat_inv, trans_mat, 0); for(i = 0; i < symmetry->size; i++) { mat_copy_matrix_i3(sym_tmp->rot[i], symmetry->rot[i]); mat_copy_vector_d3(sym_tmp->trans[i], symmetry->trans[i]); } for(i = 0; i < symmetry->size; i++) { mat_cast_matrix_3i_to_3d(drot, sym_tmp->rot[i]); mat_get_similar_matrix_d3(drot, drot, trans_mat, 0); mat_cast_matrix_3d_to_3i(sym_tmp->rot[i], drot); mat_multiply_matrix_vector_d3(sym_tmp->trans[i], trans_mat_inv, sym_tmp->trans[i]); } for(i = 0; i < symmetry->size; i++) { for(j = 0; j < multi; j++) { mat_copy_matrix_i3(symmetry_orig->rot[i * multi + j], sym_tmp->rot[i]); for (k = 0; k < 3; k++) { symmetry_orig->trans[i * multi + j][k] = sym_tmp->trans[i][k] + pure_trans->vec[j][k]; } } } sym_free_symmetry(sym_tmp); return symmetry_orig; }
VecDBL * sym_reduce_pure_translation(SPGCONST Cell * cell, const VecDBL * pure_trans, const double symprec) { int i, multi; Symmetry *symmetry, *symmetry_reduced; VecDBL * pure_trans_reduced; multi = pure_trans->size; symmetry = sym_alloc_symmetry(multi); for (i = 0; i < multi; i++) { mat_copy_matrix_i3(symmetry->rot[i], identity); mat_copy_vector_d3(symmetry->trans[i], pure_trans->vec[i]); } symmetry_reduced = reduce_operation(cell, symmetry, symprec); sym_free_symmetry(symmetry); multi = symmetry_reduced->size; pure_trans_reduced = mat_alloc_VecDBL(multi); for (i = 0; i < multi; i++) { mat_copy_vector_d3(pure_trans_reduced->vec[i], symmetry_reduced->trans[i]); } sym_free_symmetry(symmetry_reduced); return pure_trans_reduced; }
/* Return NULL if failed */ static Symmetry * copy_symmetry_upon_lattice_points(const VecDBL *pure_trans, SPGCONST Symmetry *t_sym) { int i, j, k, size_sym_orig; Symmetry *symmetry; symmetry = NULL; size_sym_orig = t_sym->size; if ((symmetry = sym_alloc_symmetry(pure_trans->size * size_sym_orig)) == NULL) { return NULL; } 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]); } } } return symmetry; }
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 Symmetry * reduce_operation(SPGCONST Cell * cell, SPGCONST Symmetry * symmetry, const double symprec) { int i, j, num_sym; Symmetry * sym_reduced; PointSymmetry point_symmetry; MatINT *rot; VecDBL *trans; debug_print("reduce_operation:\n"); point_symmetry = get_lattice_symmetry(cell, symprec); rot = mat_alloc_MatINT(symmetry->size); trans = mat_alloc_VecDBL(symmetry->size); num_sym = 0; for (i = 0; i < point_symmetry.size; i++) { for (j = 0; j < symmetry->size; j++) { if (mat_check_identity_matrix_i3(point_symmetry.rot[i], symmetry->rot[j])) { if (is_overlap_all_atoms(symmetry->trans[j], symmetry->rot[j], cell, symprec, 0)) { mat_copy_matrix_i3(rot->mat[num_sym], symmetry->rot[j]); mat_copy_vector_d3(trans->vec[num_sym], symmetry->trans[j]); num_sym++; } } } } sym_reduced = sym_alloc_symmetry(num_sym); for (i = 0; i < num_sym; i++) { mat_copy_matrix_i3(sym_reduced->rot[i], rot->mat[i]); mat_copy_vector_d3(sym_reduced->trans[i], trans->vec[i]); } mat_free_MatINT(rot); mat_free_VecDBL(trans); debug_print(" num_sym %d -> %d\n", symmetry->size, num_sym); return sym_reduced; }
static Symmetry * get_db_symmetry(const int hall_number) { int i; int operation_index[2]; int rot[3][3]; double trans[3]; Symmetry *symmetry; spgdb_get_operation_index(operation_index, hall_number); symmetry = sym_alloc_symmetry(operation_index[0]); for (i = 0; i < operation_index[0]; i++) { /* rotation matrix matching and set difference of translations */ spgdb_get_operation(rot, trans, operation_index[1] + i); mat_copy_matrix_i3(symmetry->rot[i], rot); mat_copy_vector_d3(symmetry->trans[i], trans); } return symmetry; }
Symmetry * sym_get_operation( SPGCONST Cell *cell, const double symprec ) { int i, j, num_sym; MatINT *rot; VecDBL *trans; Symmetry *symmetry; rot = mat_alloc_MatINT( cell->size * 48 ); trans = mat_alloc_VecDBL( cell->size * 48 ); num_sym = get_operation( rot->mat, trans->vec, cell, symprec ); #ifdef DEBUG debug_print("*** get_symmetry (found symmetry operations) *** \n"); debug_print("Lattice \n"); debug_print_matrix_d3(cell->lattice); for ( i = 0; i < num_sym; i++ ) { debug_print("--- %d ---\n", i + 1); debug_print_matrix_i3(rot->mat[i]); debug_print("%f %f %f\n", trans->vec[i][0], trans->vec[i][1], trans->vec[i][2]); } #endif symmetry = sym_alloc_symmetry( num_sym ); for ( i = 0; i < num_sym; i++ ) { mat_copy_matrix_i3(symmetry->rot[i], rot->mat[i]); for (j = 0; j < 3; j++) symmetry->trans[i][j] = trans->vec[i][j]; } mat_free_MatINT( rot ); mat_free_VecDBL( trans ); return symmetry; }
static Symmetry * get_space_group_operations(SPGCONST PointSymmetry *lattice_sym, SPGCONST Cell *cell, const double symprec) { int i, j, num_sym, total_num_sym; VecDBL **trans; Symmetry *symmetry; debug_print("get_space_group_operations:\n"); trans = (VecDBL**) malloc(sizeof(VecDBL*) * lattice_sym->size); total_num_sym = 0; for (i = 0; i < lattice_sym->size; i++) { trans[i] = get_translation(lattice_sym->rot[i], cell, symprec, 0); total_num_sym += trans[i]->size; } symmetry = sym_alloc_symmetry(total_num_sym); num_sym = 0; for (i = 0; i < lattice_sym->size; i++) { for (j = 0; j < trans[i]->size; j++) { mat_copy_vector_d3(symmetry->trans[num_sym + j], trans[i]->vec[j]); mat_copy_matrix_i3(symmetry->rot[num_sym + j], lattice_sym->rot[i]); } num_sym += trans[i]->size; } for (i = 0; i < lattice_sym->size; i++) { mat_free_VecDBL(trans[i]); } free(trans); trans = NULL; return symmetry; }
/* 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; }
/* was not a primitive cell. */ static Symmetry * get_operations(SPGCONST Cell *cell, const double symprec) { int i, j, attempt; double tolerance; PointSymmetry lattice_sym; Symmetry *symmetry, *symmetry_orig, *symmetry_reduced; Primitive primitive; debug_print("get_operations:\n"); symmetry_orig = NULL; lattice_sym = get_lattice_symmetry(cell, symprec); if (lattice_sym.size == 0) { debug_print("get_lattice_symmetry failed.\n"); goto end; } primitive = prm_get_primitive_and_pure_translations(cell, symprec); if (primitive.cell->size == 0) { goto deallocate_and_end; } lattice_sym = transform_pointsymmetry(&lattice_sym, primitive.cell->lattice, cell->lattice); if (lattice_sym.size == 0) { goto deallocate_and_end; } symmetry = get_space_group_operations(&lattice_sym, primitive.cell, symprec); if (symmetry->size > 48) { tolerance = symprec; for (attempt = 0; attempt < 100; attempt++) { tolerance *= REDUCE_RATE; warning_print("spglib: number of symmetry operations for primitive cell > 48 was found. (line %d, %s).\n", __LINE__, __FILE__); warning_print("tolerance is reduced to %f\n", tolerance); symmetry_reduced = reduce_operation(primitive.cell, symmetry, tolerance); sym_free_symmetry(symmetry); symmetry = symmetry_reduced; if (symmetry_reduced->size > 48) { ; } else { break; } } } symmetry_orig = recover_operations_original(symmetry, primitive.pure_trans, cell, primitive.cell); sym_free_symmetry(symmetry); for (i = 0; i < symmetry_orig->size; i++) { for (j = 0; j < 3; j++) { symmetry_orig->trans[i][j] -= mat_Nint(symmetry_orig->trans[i][j]); } } deallocate_and_end: cel_free_cell(primitive.cell); mat_free_VecDBL(primitive.pure_trans); end: if (! symmetry_orig) { symmetry_orig = sym_alloc_symmetry(0); } return symmetry_orig; }
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; }
/* Return NULL if failed */ static Symmetry * get_space_group_operations(SPGCONST PointSymmetry *lattice_sym, SPGCONST Cell *primitive, const double symprec) { int i, j, num_sym, total_num_sym; VecDBL **trans; Symmetry *symmetry; debug_print("get_space_group_operations (tolerance = %f):\n", symprec); trans = NULL; symmetry = NULL; if ((trans = (VecDBL**) malloc(sizeof(VecDBL*) * lattice_sym->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return NULL; } for (i = 0; i < lattice_sym->size; i++) { trans[i] = NULL; } total_num_sym = 0; for (i = 0; i < lattice_sym->size; i++) { if ((trans[i] = get_translation(lattice_sym->rot[i], primitive, symprec, 0)) != NULL) { debug_print(" match translation %d/%d; tolerance = %f\n", i + 1, lattice_sym->size, symprec); total_num_sym += trans[i]->size; } } if ((symmetry = sym_alloc_symmetry(total_num_sym)) == NULL) { goto ret; } num_sym = 0; for (i = 0; i < lattice_sym->size; i++) { if (trans[i] == NULL) { continue; } for (j = 0; j < trans[i]->size; j++) { mat_copy_vector_d3(symmetry->trans[num_sym + j], trans[i]->vec[j]); mat_copy_matrix_i3(symmetry->rot[num_sym + j], lattice_sym->rot[i]); } num_sym += trans[i]->size; } ret: for (i = 0; i < lattice_sym->size; i++) { if (trans[i] != NULL) { mat_free_VecDBL(trans[i]); trans[i] = NULL; } } free(trans); trans = NULL; return symmetry; }
/* Return 0 if failed */ static int get_symmetry_with_collinear_spin(int rotation[][3][3], double translation[][3], int equivalent_atoms[], const int max_size, SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const double spins[], const int num_atom, const double symprec) { int i, size; Symmetry *symmetry, *sym_nonspin; Cell *cell; SpglibDataset *dataset; size = 0; symmetry = NULL; sym_nonspin = NULL; cell = NULL; dataset = NULL; if ((cell = cel_alloc_cell(num_atom)) == NULL) { goto err; } cel_set_cell(cell, lattice, position, types); if ((dataset = get_dataset(lattice, position, types, num_atom, 0, symprec)) == NULL) { cel_free_cell(cell); goto err; } if ((sym_nonspin = sym_alloc_symmetry(dataset->n_operations)) == NULL) { spg_free_dataset(dataset); cel_free_cell(cell); goto err; } for (i = 0; i < dataset->n_operations; i++) { mat_copy_matrix_i3(sym_nonspin->rot[i], dataset->rotations[i]); mat_copy_vector_d3(sym_nonspin->trans[i], dataset->translations[i]); } spg_free_dataset(dataset); if ((symmetry = spn_get_collinear_operations(equivalent_atoms, sym_nonspin, cell, spins, symprec)) == NULL) { sym_free_symmetry(sym_nonspin); cel_free_cell(cell); goto err; } sym_free_symmetry(sym_nonspin); if (symmetry->size > max_size) { fprintf(stderr, "spglib: Indicated max size(=%d) is less than number ", max_size); fprintf(stderr, "spglib: of symmetry operations(=%d).\n", symmetry->size); sym_free_symmetry(symmetry); goto err; } for (i = 0; i < symmetry->size; i++) { mat_copy_matrix_i3(rotation[i], symmetry->rot[i]); mat_copy_vector_d3(translation[i], symmetry->trans[i]); } size = symmetry->size; cel_free_cell(cell); sym_free_symmetry(symmetry); return size; err: return 0; }
/* Return NULL if failed */ static Symmetry * reduce_operation(SPGCONST Cell * primitive, SPGCONST Symmetry * symmetry, const double symprec, const double angle_symprec) { int i, j, num_sym; Symmetry * sym_reduced; PointSymmetry point_symmetry; MatINT *rot; VecDBL *trans; debug_print("reduce_operation:\n"); sym_reduced = NULL; rot = NULL; trans = NULL; point_symmetry = get_lattice_symmetry(primitive->lattice, symprec, angle_symprec); if (point_symmetry.size == 0) { return NULL; } if ((rot = mat_alloc_MatINT(symmetry->size)) == NULL) { return NULL; } if ((trans = mat_alloc_VecDBL(symmetry->size)) == NULL) { mat_free_MatINT(rot); rot = NULL; return NULL; } num_sym = 0; for (i = 0; i < point_symmetry.size; i++) { for (j = 0; j < symmetry->size; j++) { if (mat_check_identity_matrix_i3(point_symmetry.rot[i], symmetry->rot[j])) { if (is_overlap_all_atoms(symmetry->trans[j], symmetry->rot[j], primitive, symprec, 0)) { mat_copy_matrix_i3(rot->mat[num_sym], symmetry->rot[j]); mat_copy_vector_d3(trans->vec[num_sym], symmetry->trans[j]); num_sym++; } } } } if ((sym_reduced = sym_alloc_symmetry(num_sym)) != NULL) { for (i = 0; i < num_sym; i++) { mat_copy_matrix_i3(sym_reduced->rot[i], rot->mat[i]); mat_copy_vector_d3(sym_reduced->trans[i], trans->vec[i]); } } mat_free_MatINT(rot); rot = NULL; mat_free_VecDBL(trans); trans = NULL; return sym_reduced; }
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 tmp_trans; double tmp_matrix_d3[3][3], shift[4][3]; double symmetry_rot_d3[3][3], primitive_sym_rot_d3[3][3]; Symmetry *symmetry; size = primitive_sym->size; if (centering == FACE) { symmetry = sym_alloc_symmetry(size * 4); } else { if (centering) { symmetry = sym_alloc_symmetry(size * 2); } else { symmetry = sym_alloc_symmetry(size); } } 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(tmp_matrix_d3, transform_mat, 0); mat_multiply_matrix_vector_d3(symmetry->trans[i], tmp_matrix_d3, primitive_sym->trans[i]); } multi = 1; if (centering) { if (! (centering == FACE)) { for (i = 0; i < 3; i++) { shift[0][i] = 0.5; } 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 == 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++) { tmp_trans = symmetry->trans[j][k] + shift[i][k]; symmetry->trans[(i+1) * size + j][k] = tmp_trans; } } } } /* Reduce translations into -0 < trans < 1.0 */ for (i = 0; i < multi; i++) { for (j = 0; j < size; j++) { for (k = 0; k < 3; k++) { tmp_trans = symmetry->trans[i * size + j][k]; tmp_trans -= mat_Nint(tmp_trans); if (tmp_trans < 0) { tmp_trans += 1.0; } symmetry->trans[i * size + j][k] = tmp_trans; } } } 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; }
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; }