static int get_Wyckoff_notation(double position[3], SPGCONST Symmetry * conv_sym, SPGCONST double bravais_lattice[3][3], const int hall_number, const double symprec) { int i, j, k, l, at_orbit, num_sitesym, wyckoff_letter=-1; int indices_wyc[2]; int rot[3][3]; double trans[3], orbit[3]; VecDBL *pos_rot; pos_rot = mat_alloc_VecDBL(conv_sym->size); for (i = 0; i < conv_sym->size; i++) { mat_multiply_matrix_vector_id3(pos_rot->vec[i], conv_sym->rot[i], position); for (j = 0; j < 3; j++) { pos_rot->vec[i][j] += conv_sym->trans[i][j]; } } ssmdb_get_wyckoff_indices(indices_wyc, hall_number); for (i = 0; i < indices_wyc[1]; i++) { num_sitesym = ssmdb_get_coordinate(rot, trans, i + indices_wyc[0]); for (j = 0; j < pos_rot->size; j++) { at_orbit = 0; for (k = 0; k < pos_rot->size; k++) { if (cel_is_overlap(pos_rot->vec[j], pos_rot->vec[k], bravais_lattice, symprec)) { mat_multiply_matrix_vector_id3(orbit, rot, pos_rot->vec[k]); for (l = 0; l < 3; l++) { orbit[l] += trans[l]; } if (cel_is_overlap(pos_rot->vec[k], orbit, bravais_lattice, symprec)) { at_orbit++; } } } if (at_orbit == conv_sym->size / num_sitesym) { /* Database is made reversed order, e.g., gfedcba. */ /* wyckoff is set 0 1 2 3 4... for a b c d e..., respectively. */ wyckoff_letter = indices_wyc[1] - i - 1; goto end; } } } end: mat_free_VecDBL(pos_rot); return wyckoff_letter; }
/* 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 VecDBL * reduce_lattice_points(SPGCONST double lattice[3][3], const VecDBL *lattice_trans, const double symprec) { int i, j, is_found, num_pure_trans; VecDBL *pure_trans, *t; num_pure_trans = 0; t = mat_alloc_VecDBL(lattice_trans->size); for (i = 0; i < lattice_trans->size; i++) { is_found = 0; for (j = 0; j < num_pure_trans; 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_pure_trans], lattice_trans->vec[i]); num_pure_trans++; } } pure_trans = mat_alloc_VecDBL(num_pure_trans); for (i = 0; i < num_pure_trans; i++) { mat_copy_vector_d3(pure_trans->vec[i], t->vec[i]); } mat_free_VecDBL(t); return pure_trans; }
/* Return 0 if failed */ static int get_overlap_table(int **overlap_table, SPGCONST Cell *primitive_cell, const VecDBL * position, const int *types, const double symprec) { int i, j, attempt, num_overlap, ratio, cell_size; double trim_tolerance; cell_size = position->size; ratio = cell_size / primitive_cell->size; trim_tolerance = symprec; for (attempt = 0; attempt < 100; attempt++) { /* Each value of -1 has to be overwritten by 0 or positive numbers. */ for (i = 0; i < cell_size; i++) { for (j = 0; j < cell_size; j++) { overlap_table[i][j] = -1; } } for (i = 0; i < cell_size; i++) { num_overlap = 0; for (j = 0; j < cell_size; j++) { if (types[i] == types[j]) { if (cel_is_overlap(position->vec[i], position->vec[j], primitive_cell->lattice, trim_tolerance)) { overlap_table[i][num_overlap] = j; num_overlap++; } } } } if (check_overlap_table(overlap_table, cell_size, ratio)) { goto found; } if (num_overlap < ratio) { trim_tolerance *= INCREASE_RATE; warning_print("spglib: Increase tolerance to %f ", trim_tolerance); } else { trim_tolerance *= REDUCE_RATE; warning_print("spglib: Reduce tolerance to %f ", trim_tolerance); } warning_print("(line %d, %s).\n", __LINE__, __FILE__); } warning_print("spglib: Could not trim cell into primitive "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); return 0; found: return 1; }
/* Return 0 if failed */ static int set_equivalent_atoms(int * equiv_atoms, SPGCONST Symmetry *symmetry, SPGCONST Cell * cell, const double symprec) { int i, j, k, is_found; double pos[3]; int *mapping_table; mapping_table = NULL; if ((mapping_table = get_mapping_table(symmetry, cell, symprec)) == NULL) { return 0; } for (i = 0; i < cell->size; i++) { if (mapping_table[i] != i) { continue; } is_found = 0; for (j = 0; j < symmetry->size; j++) { mat_multiply_matrix_vector_id3(pos, symmetry->rot[j], cell->position[i]); for (k = 0; k < 3; k++) { pos[k] += symmetry->trans[j][k]; } for (k = 0; k < cell->size; k++) { if (cel_is_overlap(pos, cell->position[k], cell->lattice, symprec)) { if (mapping_table[k] < i) { equiv_atoms[i] = equiv_atoms[mapping_table[k]]; is_found = 1; break; } } } if (is_found) { break; } } if (!is_found) { equiv_atoms[i] = i; } } for (i = 0; i < cell->size; i++) { if (mapping_table[i] == i) { continue; } equiv_atoms[i] = equiv_atoms[mapping_table[i]]; } free(mapping_table); mapping_table = NULL; return 1; }
int cel_is_overlap_with_same_type(const double a[3], const double b[3], const int type_a, const int type_b, SPGCONST double lattice[3][3], const double symprec) { if (type_a == type_b) { return cel_is_overlap(a, b, lattice, symprec); } else { return 0; } }
/* 0: No overlap of atoms was found. */ int cel_any_overlap(const Cell * cell, const double symprec) { int i, j; for (i = 0; i < cell->size; i++) { for (j = i + 1; j < cell->size; j++) { if (cel_is_overlap(cell->position[i], cell->position[j], cell->lattice, symprec)) { return 1; } } } return 0; }
/* Return NULL if failed */ static int * get_mapping_table(SPGCONST Symmetry *symmetry, SPGCONST Cell * cell, const double symprec) { int i, j, k, is_found; double pos[3]; int *mapping_table; SPGCONST int I[3][3] = {{ 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}}; mapping_table = NULL; if ((mapping_table = (int*) malloc(sizeof(int) * cell->size)) == NULL) { warning_print("spglib: Memory could not be allocated."); return NULL; } for (i = 0; i < cell->size; i++) { is_found = 0; for (j = 0; j < symmetry->size; j++) { if (mat_check_identity_matrix_i3(symmetry->rot[j], I)) { for (k = 0; k < 3; k++) { pos[k] = cell->position[i][k] + symmetry->trans[j][k]; } for (k = 0; k < cell->size; k++) { if (cel_is_overlap(pos, cell->position[k], cell->lattice, symprec)) { if (k < i) { mapping_table[i] = mapping_table[k]; is_found = 1; break; } } } } if (is_found) { break; } } if (!is_found) { mapping_table[i] = i; } } return mapping_table; }
static int search_equivalent_atom(const int atom_index, SPGCONST Cell * cell, const Symmetry *symmetry, const double symprec) { int i, j; double pos_rot[3]; for (i = 0; i < symmetry->size; i++) { mat_multiply_matrix_vector_id3(pos_rot, symmetry->rot[i], cell->position[atom_index]); for (j = 0; j < 3; j++) { pos_rot[j] += symmetry->trans[i][j]; } for (j = 0; j < atom_index; j++) { if (cel_is_overlap(cell->position[j], pos_rot, cell->lattice, symprec)) { return j; } } } return atom_index; }
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; }
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 int * get_overlap_table(const VecDBL * position, const int cell_size, const int * cell_types, const Cell * trimmed_cell, const double symprec) { int i, j, attempt, num_overlap, ratio; double trim_tolerance; int *overlap_table; trim_tolerance = symprec; ratio = cell_size / trimmed_cell->size; if ((overlap_table = (int*)malloc(sizeof(int) * cell_size)) == NULL) { return NULL; } for (attempt = 0; attempt < NUM_ATTEMPT; attempt++) { for (i = 0; i < cell_size; i++) { overlap_table[i] = i; for (j = 0; j < cell_size; j++) { if (cell_types[i] == cell_types[j]) { if (cel_is_overlap(position->vec[i], position->vec[j], trimmed_cell->lattice, trim_tolerance)) { if (overlap_table[j] == j) { overlap_table[i] = j; break; } } } } } for (i = 0; i < cell_size; i++) { if (overlap_table[i] != i) { continue; } num_overlap = 0; for (j = 0; j < cell_size; j++) { if (i == overlap_table[j]) { num_overlap++; } } if (num_overlap == ratio) { continue; } if (num_overlap < ratio) { trim_tolerance *= INCREASE_RATE; warning_print("spglib: Increase tolerance to %f ", trim_tolerance); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto cont; } if (num_overlap > ratio) { trim_tolerance *= REDUCE_RATE; warning_print("spglib: Reduce tolerance to %f ", trim_tolerance); warning_print("(%d) ", attempt); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto cont; } } goto found; cont: ; } warning_print("spglib: Could not trim cell well "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); free(overlap_table); overlap_table = NULL; found: return overlap_table; }
static int get_overlap_table( int **overlap_table, const int cell_size, SPGCONST Cell *primitive, const VecDBL * position, const double symprec ) { int i, j, is_found, attempt, count, ratio; int count_error=0, old_count_error=0; double trim_tolerance, tol_adjust; ratio = cell_size / primitive->size; trim_tolerance = symprec; tol_adjust = trim_tolerance/2.0; is_found = 0; /* Break when is_found */ for ( attempt = 0; attempt < 1000; attempt++ ) { is_found = 1; debug_print("Trim attempt %d: tolerance=%f\n",attempt+1,trim_tolerance); /* Each value of -1 has to be overwritten by 0 or positive numbers. */ for (i = 0; i < cell_size; i++) { for (j = 0; j < cell_size; j++) { overlap_table[i][j] = -1; } } for (i = 0; i < cell_size; i++) { count = 0; for (j = 0; j < cell_size; j++) { if ( cel_is_overlap( position->vec[i], position->vec[j], primitive->lattice, trim_tolerance ) ) { overlap_table[i][count] = j; count++; } } /* Adjust tolerance to avoid too much and too few overlaps */ if (count != ratio) { /* check overlapping number */ count_error = count - ratio; /* Initialize count error if needed: */ if (old_count_error == 0) { old_count_error = count - ratio; } /* Adjust the tolerance adjustment if needed */ if ( ( old_count_error > 0 && count_error < 0 ) || ( old_count_error < 0 && count_error > 0 ) || trim_tolerance - tol_adjust <= 0 ) { tol_adjust /= 2.0; } old_count_error = count_error; debug_print("Bad tolerance: count=%d ratio=%d tol_adjust=%f\n", count,ratio,tol_adjust); if ( count_error > 0 ) { trim_tolerance -= tol_adjust; } else { trim_tolerance += tol_adjust; } is_found = 0; break; } } if ( is_found ) { break; } } if ( ! is_found ) { warning_print("spglib: Could not trim cell into primitive "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto err; } return 1; err: return 0; }
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; }
/* 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; } }