void mat_cast_matrix_3d_to_3i(int m[3][3], const double a[3][3]) { m[0][0] = mat_Nint(a[0][0]); m[0][1] = mat_Nint(a[0][1]); m[0][2] = mat_Nint(a[0][2]); m[1][0] = mat_Nint(a[1][0]); m[1][1] = mat_Nint(a[1][1]); m[1][2] = mat_Nint(a[1][2]); m[2][0] = mat_Nint(a[2][0]); m[2][1] = mat_Nint(a[2][1]); m[2][2] = mat_Nint(a[2][2]); }
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; if ( lat_smallest_lattice_vector( min_lat, cell->lattice, symprec ) ) { mat_inverse_matrix_d3( inv_lat, min_lat, 0 ); mat_multiply_matrix_d3( trans_mat, inv_lat, cell->lattice ); smallest_cell = cel_alloc_cell( cell->size ); 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_Nint( cell->position[i][j] ); } } } else { smallest_cell = cel_alloc_cell( -1 ); } return smallest_cell; }
static VecDBL * get_positions_primitive( SPGCONST Cell * cell, SPGCONST double prim_lat[3][3] ) { int i, j; double tmp_matrix[3][3], axis_inv[3][3]; VecDBL * position; position = mat_alloc_VecDBL( cell->size ); mat_inverse_matrix_d3(tmp_matrix, prim_lat, 0); mat_multiply_matrix_d3(axis_inv, tmp_matrix, cell->lattice); /* Send atoms into the primitive cell */ debug_print("Positions in new axes reduced to primitive cell\n"); for (i = 0; i < cell->size; i++) { mat_multiply_matrix_vector_d3( position->vec[i], axis_inv, cell->position[i] ); for (j = 0; j < 3; j++) { position->vec[i][j] -= mat_Nint( position->vec[i][j] ); } debug_print("%d: %f %f %f\n", i + 1, position->vec[i][0], position->vec[i][1], position->vec[i][2]); } return position; }
/* Return NULL if failed */ static VecDBL * get_positions_primitive(SPGCONST Cell * cell, SPGCONST double prim_lat[3][3]) { int i, j; double tmp_matrix[3][3], axis_inv[3][3]; VecDBL * position; position = NULL; if ((position = mat_alloc_VecDBL(cell->size)) == NULL) { return NULL; } mat_inverse_matrix_d3(tmp_matrix, prim_lat, 0); mat_multiply_matrix_d3(axis_inv, tmp_matrix, cell->lattice); /* Send atoms into the primitive cell */ for (i = 0; i < cell->size; i++) { mat_multiply_matrix_vector_d3(position->vec[i], axis_inv, cell->position[i]); for (j = 0; j < 3; j++) { position->vec[i][j] -= mat_Nint(position->vec[i][j]); } } return position; }
/* 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]; } }
static Cell * get_conventional_primitive(SPGCONST Spacegroup * spacegroup, SPGCONST Cell * primitive) { int i, j; double inv_brv[3][3], trans_mat[3][3]; Cell * conv_prim; conv_prim = cel_alloc_cell(primitive->size); mat_inverse_matrix_d3(inv_brv, spacegroup->bravais_lattice, 0); mat_multiply_matrix_d3(trans_mat, inv_brv, primitive->lattice); for (i = 0; i < primitive->size; i++) { conv_prim->types[i] = primitive->types[i]; mat_multiply_matrix_vector_d3(conv_prim->position[i], trans_mat, primitive->position[i]); for (j = 0; j < 3; j++) { conv_prim->position[i][j] -= spacegroup->origin_shift[j]; conv_prim->position[i][j] -= mat_Nint(conv_prim->position[i][j]); } } return conv_prim; }
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; }
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; }
int mat_is_int_matrix(SPGCONST double mat[3][3], const double symprec) { int i,j ; for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 3; j++ ) { if ( mat_Dabs( mat_Nint( mat[i][j] ) - mat[i][j] ) > symprec ) { return 0; } } } return 1; }
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; }
void cel_set_cell(Cell * cell, SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[]) { int i, j; mat_copy_matrix_d3(cell->lattice, lattice); for (i = 0; i < cell->size; i++) { for (j = 0; j < 3; j++) { cell->position[i][j] = position[i][j] - mat_Nint(position[i][j]); } cell->types[i] = types[i]; } }
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; }
int cel_is_overlap( const double a[3], const double b[3], SPGCONST double lattice[3][3], const double symprec ) { int i; double v_diff[3]; for ( i = 0; i < 3; i++ ) { v_diff[i] = a[i] - b[i]; v_diff[i] -= mat_Nint( v_diff[i] ); } mat_multiply_matrix_vector_d3( v_diff, lattice, v_diff ); if ( mat_norm_squared_d3( v_diff ) < symprec*symprec ) { return 1; } else { return 0; } }
/* 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_Nint(cell->position[i][j]); } } return smallest_cell; err: return NULL; }
/* 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_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 0 if failed */ static int set_primitive_positions(Cell * primitive_cell, const VecDBL * position, const Cell * cell, int * const * table) { int i, j, k, ratio, index_prim_atom; int *is_equivalent; is_equivalent = NULL; if ((is_equivalent = (int*) malloc(cell->size * sizeof(int))) == NULL) { warning_print("spglib: Memory could not be allocated "); goto err; } for (i = 0; i < cell->size; i++) { is_equivalent[i] = 0; } ratio = cell->size / primitive_cell->size; /* Copy positions. Positions of overlapped atoms are averaged. */ index_prim_atom = 0; for (i = 0; i < cell->size; i++) { if (! is_equivalent[i]) { primitive_cell->types[index_prim_atom] = cell->types[i]; for (j = 0; j < 3; j++) { primitive_cell->position[index_prim_atom][j] = 0; } for (j = 0; j < ratio; j++) { /* Loop for averaging positions */ is_equivalent[table[i][j]] = 1; for (k = 0; k < 3; k++) { /* boundary treatment */ /* One is at right and one is at left or vice versa. */ if (mat_Dabs(position->vec[table[i][0]][k] - position->vec[table[i][j]][k]) > 0.5) { if (position->vec[table[i][j]][k] < 0) { primitive_cell->position[index_prim_atom][k] = primitive_cell->position[index_prim_atom][k] + position->vec[table[i][j]][k] + 1; } else { primitive_cell->position[index_prim_atom][k] = primitive_cell->position[index_prim_atom][k] + position->vec[table[i][j]][k] - 1; } } else { primitive_cell->position[index_prim_atom][k] = primitive_cell->position[index_prim_atom][k] + position->vec[table[i][j]][k]; } } } for (j = 0; j < 3; j++) { /* take average and reduce */ primitive_cell->position[index_prim_atom][j] = primitive_cell->position[index_prim_atom][j] / ratio; primitive_cell->position[index_prim_atom][j] = primitive_cell->position[index_prim_atom][j] - mat_Nint(primitive_cell->position[index_prim_atom][j]); } index_prim_atom++; } } free(is_equivalent); is_equivalent = NULL; if (! (index_prim_atom == primitive_cell->size)) { warning_print("spglib: Atomic positions of primitive cell could not be determined "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto err; } return 1; err: return 0; }
/* Return 0 if failed */ static int get_primitive_lattice_vectors(double prim_lattice[3][3], const VecDBL * vectors, SPGCONST Cell * cell, const double symprec) { int i, j, k, size; double initial_volume, volume; double relative_lattice[3][3], min_vectors[3][3], tmp_lattice[3][3]; double inv_mat_dbl[3][3]; int inv_mat_int[3][3]; debug_print("get_primitive_lattice_vectors:\n"); size = vectors->size; initial_volume = mat_Dabs(mat_get_determinant_d3(cell->lattice)); /* check volumes of all possible lattices, find smallest volume */ for (i = 0; i < size; i++) { for (j = i + 1; j < size; j++) { for (k = j + 1; k < size; k++) { mat_multiply_matrix_vector_d3(tmp_lattice[0], cell->lattice, vectors->vec[i]); mat_multiply_matrix_vector_d3(tmp_lattice[1], cell->lattice, vectors->vec[j]); mat_multiply_matrix_vector_d3(tmp_lattice[2], cell->lattice, vectors->vec[k]); volume = mat_Dabs(mat_get_determinant_d3(tmp_lattice)); if (volume > symprec) { if (mat_Nint(initial_volume / volume) == size-2) { mat_copy_vector_d3(min_vectors[0], vectors->vec[i]); mat_copy_vector_d3(min_vectors[1], vectors->vec[j]); mat_copy_vector_d3(min_vectors[2], vectors->vec[k]); goto ret; } } } } } /* Not found */ warning_print("spglib: Primitive lattice vectors cound not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); return 0; /* Found */ ret: for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { relative_lattice[j][i] = min_vectors[i][j]; } } mat_inverse_matrix_d3(inv_mat_dbl, relative_lattice, 0); mat_cast_matrix_3d_to_3i(inv_mat_int, inv_mat_dbl); if (abs(mat_get_determinant_i3(inv_mat_int)) == size-2) { mat_cast_matrix_3i_to_3d(inv_mat_dbl, inv_mat_int); mat_inverse_matrix_d3(relative_lattice, inv_mat_dbl, 0); } else { warning_print("spglib: Primitive lattice cleaning is incomplete "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); } mat_multiply_matrix_d3(prim_lattice, cell->lattice, relative_lattice); return 1; }
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; }
/* 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; } }
static int set_primitive_positions( Cell * primitive, const VecDBL * position, const Cell * cell, int * const * table ) { int i, j, k, ratio, count; int *is_equivalent = (int*)malloc(cell->size * sizeof(int)); ratio = cell->size / primitive->size; for (i = 0; i < cell->size; i++) { is_equivalent[i] = 0; } /* Copy positions. Positions of overlapped atoms are averaged. */ count = 0; for ( i = 0; i < cell->size; i++ ) if ( ! is_equivalent[i] ) { debug_print("Trimming... i=%d count=%d\n", i, count); primitive->types[count] = cell->types[i]; for ( j = 0; j < 3; j++ ) { primitive->position[count][j] = 0; } for ( j = 0; j < ratio; j++ ) { /* overlap atoms */ if ( table[i][j] < 0 ) { /* check if table is correctly bulit. */ break; } is_equivalent[table[i][j]] = 1; for (k = 0; k < 3; k++) { /* boundary treatment */ if (mat_Dabs(position->vec[table[i][0]][k] - position->vec[table[i][j]][k]) > 0.5) { if (position->vec[table[i][j]][k] < 0) { primitive->position[count][k] = primitive->position[count][k] + position->vec[table[i][j]][k] + 1; } else { primitive->position[count][k] = primitive->position[count][k] + position->vec[table[i][j]][k] - 1; } } else { primitive->position[count][k] = primitive->position[count][k] + position->vec[table[i][j]][k]; } } } for (j = 0; j < 3; j++) { /* take average and reduce */ primitive->position[count][j] = primitive->position[count][j] / ratio; primitive->position[count][j] = primitive->position[count][j] - mat_Nint( primitive->position[count][j] ); } count++; } free(is_equivalent); is_equivalent = NULL; debug_print("Count: %d Size of cell: %d Size of primitive: %d\n", count, cell->size, primitive->size); if ( ! ( count == primitive->size ) ) { warning_print("spglib: Atomic positions of primitive cell could not be determined "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto err; } return 1; err: 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; }
/* Return NULL if failed */ static Cell * trim_cell(int * mapping_table, SPGCONST double trimmed_lattice[3][3], const Cell * cell, const double symprec) { int i, index_atom, ratio; Cell *trimmed_cell; VecDBL * position; int *overlap_table; position = NULL; overlap_table = NULL; trimmed_cell = NULL; ratio = abs(mat_Nint(mat_get_determinant_d3(cell->lattice) / mat_get_determinant_d3(trimmed_lattice))); /* Check if cell->size is dividable by ratio */ if ((cell->size / ratio) * ratio != cell->size) { return NULL; } if ((trimmed_cell = cel_alloc_cell(cell->size / ratio)) == NULL) { return NULL; } if ((position = translate_atoms_in_trimmed_lattice(cell, trimmed_lattice)) == NULL) { cel_free_cell(trimmed_cell); trimmed_cell = NULL; goto err; } mat_copy_matrix_d3(trimmed_cell->lattice, trimmed_lattice); if ((overlap_table = get_overlap_table(position, cell->size, cell->types, trimmed_cell, symprec)) == NULL) { mat_free_VecDBL(position); position = NULL; cel_free_cell(trimmed_cell); trimmed_cell = NULL; goto err; } index_atom = 0; for (i = 0; i < cell->size; i++) { if (overlap_table[i] == i) { mapping_table[i] = index_atom; trimmed_cell->types[index_atom] = cell->types[i]; index_atom++; } else { mapping_table[i] = mapping_table[overlap_table[i]]; } } set_positions(trimmed_cell, position, mapping_table, overlap_table); mat_free_VecDBL(position); position = NULL; free(overlap_table); return trimmed_cell; err: return NULL; }