/* If primitive could not be found, primitive->size = 0 is returned. */ static Cell * get_primitive(int * mapping_table, SPGCONST Cell * cell, const VecDBL * pure_trans, const double symprec) { int multi; double prim_lattice[3][3]; Cell * primitive_cell; debug_print("get_primitive:\n"); /* Primitive lattice vectors are searched. */ /* To be consistent, sometimes tolerance is decreased iteratively. */ /* The descreased tolerance is stored in 'static double tolerance'. */ multi = get_primitive_lattice_vectors_iterative(prim_lattice, cell, pure_trans, symprec); if (! multi) { goto not_found; } primitive_cell = cel_alloc_cell(cell->size / multi); if (! lat_smallest_lattice_vector(primitive_cell->lattice, prim_lattice, symprec)) { cel_free_cell(primitive_cell); goto not_found; } /* Fit atoms into new primitive cell */ if (! trim_cell(primitive_cell, mapping_table, cell, symprec)) { cel_free_cell(primitive_cell); goto not_found; } /* found */ return primitive_cell; not_found: primitive_cell = cel_alloc_cell(0); warning_print("spglib: Primitive cell could not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); return primitive_cell; }
static NiggliParams * initialize(const double *lattice_, const double eps_) { NiggliParams * p; p = NULL; if ((p = (NiggliParams*)malloc(sizeof(NiggliParams))) == NULL) { warning_print("niggli: Memory could not be allocated."); return NULL; } p->A = 0; p->B = 0; p->C = 0; p->eta = 0; p->xi = 0; p->zeta = 0; p->eps = 0; p->l = 0; p->m = 0; p->n = 0; p->tmat = NULL; p->lattice = NULL; if ((p->tmat = (double*)malloc(sizeof(double) * 9)) == NULL) { warning_print("niggli: Memory could not be allocated."); free(p); p = NULL; return NULL; } p->eps = eps_; if ((p->lattice = (double*)malloc(sizeof(double) * 9)) == NULL) { warning_print("niggli: Memory could not be allocated."); free(p->tmat); p->tmat = NULL; free(p); p = NULL; return NULL; } memcpy(p->lattice, lattice_, sizeof(double) * 9); return p; }
/* Return spacegroup.number = 0 if failed */ static Spacegroup search_spacegroup(SPGCONST Cell * primitive, const int candidates[], const int num_candidates, const double symprec) { int hall_number; double conv_lattice[3][3]; double origin_shift[3]; Spacegroup spacegroup; Symmetry *symmetry; PointSymmetry pointsym; debug_print("search_spacegroup (tolerance = %f):\n", symprec); symmetry = NULL; hall_number = 0; spacegroup.number = 0; if ((symmetry = sym_get_operation(primitive, symprec)) == NULL) { goto ret; } pointsym = ptg_get_pointsymmetry(symmetry->rot, symmetry->size); if (pointsym.size < symmetry->size) { warning_print("spglib: Point symmetry of primitive cell is broken. "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); sym_free_symmetry(symmetry); symmetry = NULL; goto ret; } hall_number = iterative_search_hall_number(origin_shift, conv_lattice, candidates, num_candidates, primitive, symmetry, symprec); sym_free_symmetry(symmetry); symmetry = NULL; spacegroup = get_spacegroup(hall_number, origin_shift, conv_lattice); ret: return spacegroup; }
/* NULL is returned if failed */ Primitive * spa_get_spacegroup(Spacegroup * spacegroup, SPGCONST Cell * cell, const double symprec) { int attempt; double tolerance; Primitive *primitive; debug_print("spa_get_spacegroup (tolerance = %f):\n", symprec); primitive = NULL; tolerance = symprec; for (attempt = 0; attempt < 100; attempt++) { if ((primitive = prm_get_primitive(cell, tolerance)) == NULL) { goto cont; } *spacegroup = search_spacegroup(primitive->cell, spacegroup_to_hall_number, 230, primitive->tolerance); if (spacegroup->number > 0) { break; } else { prm_free_primitive(primitive); primitive = NULL; } cont: warning_print("spglib: Attempt %d tolerance = %f failed.", attempt, tolerance); warning_print(" (line %d, %s).\n", __LINE__, __FILE__); tolerance *= REDUCE_RATE; } if (primitive == NULL) { warning_print("spglib: Space group could not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); } return primitive; }
static PointSymmetry transform_pointsymmetry(SPGCONST PointSymmetry * lat_sym_orig, SPGCONST double new_lattice[3][3], SPGCONST double original_lattice[3][3]) { int i, size; double trans_mat[3][3], inv_mat[3][3], drot[3][3]; PointSymmetry lat_sym_new; lat_sym_new.size = 0; mat_inverse_matrix_d3(inv_mat, original_lattice, 0); mat_multiply_matrix_d3(trans_mat, inv_mat, new_lattice); size = 0; for (i = 0; i < lat_sym_orig->size; i++) { mat_cast_matrix_3i_to_3d(drot, lat_sym_orig->rot[i]); mat_get_similar_matrix_d3(drot, drot, trans_mat, 0); /* new_lattice may have lower point symmetry than original_lattice.*/ /* The operations that have non-integer elements are not counted. */ if (mat_is_int_matrix(drot, mat_Dabs(mat_get_determinant_d3(trans_mat)) / 10)) { mat_cast_matrix_3d_to_3i(lat_sym_new.rot[size], drot); if (abs(mat_get_determinant_i3(lat_sym_new.rot[size])) != 1) { warning_print("spglib: A point symmetry operation is not unimodular."); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto err; } size++; } } #ifdef SPGWARNING if (! (lat_sym_orig->size == size)) { warning_print("spglib: Some of point symmetry operations were dropped."); warning_print("(line %d, %s).\n", __LINE__, __FILE__); } #endif lat_sym_new.size = size; return lat_sym_new; err: return lat_sym_new; }
VecDBL * sym_get_pure_translation(SPGCONST Cell *cell, const double symprec) { int multi; VecDBL * pure_trans; pure_trans = get_translation(identity, cell, symprec, 1); multi = pure_trans->size; if ((cell->size / multi) * multi == cell->size) { debug_print("sym_get_pure_translation: pure_trans->size = %d\n", multi); } else { ; warning_print("spglib: Finding pure translation failed (line %d, %s).\n", __LINE__, __FILE__); warning_print(" cell->size %d, multi %d\n", cell->size, multi); } return pure_trans; }
/* primitive cell with smallest lattice is returned. */ static Cell * get_primitive_and_mapping_table(int * mapping_table, SPGCONST Cell * cell, const double symprec) { int i, attempt; double tolerance; Cell *primitive_cell; VecDBL *pure_trans; tolerance = symprec; for (attempt = 0; attempt < 100; attempt++) { pure_trans = sym_get_pure_translation(cell, tolerance); if (pure_trans->size == 1) { primitive_cell = get_cell_with_smallest_lattice(cell, symprec); for (i = 0; i < cell->size; i++) { mapping_table[i] = i; } goto ret; } if (pure_trans->size > 1) { primitive_cell = get_primitive(mapping_table, cell, pure_trans, tolerance); if (primitive_cell->size > 0) { goto ret; } cel_free_cell(primitive_cell); } tolerance *= REDUCE_RATE; warning_print("spglib: Tolerance is reduced to %f at attempt %d\n", tolerance, attempt); warning_print("(line %d, %s).\n", __LINE__, __FILE__); mat_free_VecDBL(pure_trans); } /* not found: I hope this will not happen. */ warning_print("spglib: Primitive cell could not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); return cel_alloc_cell(0); ret: mat_free_VecDBL(pure_trans); set_current_tolerance(tolerance); return primitive_cell; }
/* Reference can be found in International table A. */ static int get_Delaunay_reduction( double red_lattice[3][3], SPGCONST double lattice[3][3], const double symprec ) { int i, j; double volume; double basis[4][3]; get_exteneded_basis(basis, lattice); while (1) { if (get_Delaunay_reduction_basis(basis, symprec)) { break; } } get_Delaunay_shortest_vectors( basis, symprec ); for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 3; j++ ) { red_lattice[i][j] = basis[j][i]; } } volume = mat_get_determinant_d3( red_lattice ); if ( mat_Dabs( volume ) < symprec ) { warning_print("spglib: Minimum lattice has no volume (line %d, %s).\n", __LINE__, __FILE__); goto err; } if ( volume < 0 ) { /* Flip axes */ for (i = 0; i < 3; i++) { for ( j = 0; j < 3; j++ ) { red_lattice[i][j] = -red_lattice[i][j]; } } } #ifdef DEBUG debug_print("Delaunay reduction:\n"); debug_print_matrix_d3(red_lattice); double metric[3][3]; mat_get_metric( metric, red_lattice ); debug_print("It's metric tensor.\n"); debug_print_matrix_d3( metric ); #endif return 1; err: return 0; }
/* Return NULL if failed */ Cell * spa_transform_to_primitive(SPGCONST Cell * cell, SPGCONST double trans_mat[3][3], const Centering centering, const double symprec) { int * mapping_table; double tmat[3][3], tmat_inv[3][3], prim_lat[3][3]; Cell * primitive; mapping_table = NULL; primitive = NULL; mat_inverse_matrix_d3(tmat_inv, trans_mat, 0); switch (centering) { case PRIMITIVE: mat_copy_matrix_d3(tmat, tmat_inv); break; case A_FACE: mat_multiply_matrix_d3(tmat, tmat_inv, A_mat); break; case C_FACE: mat_multiply_matrix_d3(tmat, tmat_inv, C_mat); break; case FACE: mat_multiply_matrix_d3(tmat, tmat_inv, F_mat); break; case BODY: mat_multiply_matrix_d3(tmat, tmat_inv, I_mat); break; case R_CENTER: mat_multiply_matrix_d3(tmat, tmat_inv, R_mat); break; default: goto err; } if ((mapping_table = (int*) malloc(sizeof(int) * cell->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); goto err; } mat_multiply_matrix_d3(prim_lat, cell->lattice, tmat); primitive = cel_trim_cell(mapping_table, prim_lat, cell, symprec); free(mapping_table); mapping_table = NULL; return primitive; err: return NULL; }
Spacegroup spa_get_spacegroup(SPGCONST Cell * cell, const double symprec) { double tolerance; Cell *primitive; Spacegroup spacegroup; primitive = prm_get_primitive(cell, symprec); tolerance = prm_get_current_tolerance(); if (primitive->size > 0) { spacegroup = get_spacegroup(primitive, tolerance); } else { spacegroup.number = 0; warning_print("spglib: Space group could not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); } cel_free_cell(primitive); return spacegroup; }
static Centering get_base_center( SPGCONST int transform_mat[3][3] ) { int i; Centering centering = NO_CENTER; debug_print("lat_get_base_center\n"); /* C center */ for (i = 0; i < 3; i++) { if ( transform_mat[i][0] == 0 && transform_mat[i][1] == 0 && abs( transform_mat[i][2] ) == 1 ) { centering = C_FACE; goto end; } } /* A center */ for (i = 0; i < 3; i++) { if ( abs( transform_mat[i][0] ) == 1 && transform_mat[i][1] == 0 && transform_mat[i][2] == 0 ) { centering = A_FACE; goto end; } } /* B center */ for (i = 0; i < 3; i++) { if ( transform_mat[i][0] == 0 && abs( transform_mat[i][1] ) == 1 && transform_mat[i][2] == 0 ) { centering = B_FACE; goto end; } } /* body center */ if ( abs( transform_mat[0][0] ) + abs( transform_mat[0][1] ) + abs( transform_mat[0][2] ) == 2 ) { centering = BODY; goto end; } /* This should not happen. */ warning_print("spglib: No centring was found (line %d, %s).\n", __LINE__, __FILE__); return NO_CENTER; end: debug_print("centering: %d\n", centering); return centering; }
/* Return 0 if failed */ static int get_exact_positions(VecDBL *positions, int * equiv_atoms, const Cell * conv_prim, const Symmetry * conv_sym, const double symprec) { int i, num_indep_atoms, sum_num_atoms_in_orbits, num_atoms_in_orbits; int *indep_atoms; debug_print("get_exact_positions\n"); indep_atoms = NULL; if ((indep_atoms = (int*) malloc(sizeof(int) * conv_prim->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return 0; } num_indep_atoms = 0; sum_num_atoms_in_orbits = 0; for (i = 0; i < conv_prim->size; i++) { /* Check if atom_i overlap to an atom already set at the exact position. */ if (! set_equivalent_atom(positions, equiv_atoms, i, num_indep_atoms, indep_atoms, conv_prim, conv_sym, symprec)) { /* No equivalent atom was found. */ indep_atoms[num_indep_atoms] = i; num_indep_atoms++; mat_copy_vector_d3(positions->vec[i], conv_prim->position[i]); num_atoms_in_orbits = set_exact_location(positions->vec[i], conv_sym, conv_prim->lattice, symprec); if (num_atoms_in_orbits) { sum_num_atoms_in_orbits += num_atoms_in_orbits; equiv_atoms[i] = i; } else { sum_num_atoms_in_orbits = 0; break; } } } free(indep_atoms); indep_atoms = NULL; return sum_num_atoms_in_orbits; }
static Spacegroup get_spacegroup(SPGCONST Cell * primitive, const double symprec) { int hall_number; double conv_lattice[3][3]; double origin_shift[3]; Symmetry *symmetry; Spacegroup spacegroup; SpacegroupType spacegroup_type; symmetry = sym_get_operation(primitive, symprec); if (symmetry->size == 0) { spacegroup.number = 0; warning_print("spglib: Space group could not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto ret; } hall_number = get_hall_number(origin_shift, conv_lattice, primitive, symmetry, symprec); if (hall_number == 0) { spacegroup.number = 0; warning_print("spglib: Space group could not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto ret; } spacegroup_type = spgdb_get_spacegroup_type(hall_number); if (spacegroup_type.number > 0) { mat_copy_matrix_d3(spacegroup.bravais_lattice, conv_lattice); mat_copy_vector_d3(spacegroup.origin_shift, origin_shift); spacegroup.number = spacegroup_type.number; spacegroup.hall_number = hall_number; spacegroup.holohedry = spacegroup_type.holohedry; strcpy(spacegroup.schoenflies, spacegroup_type.schoenflies); strcpy(spacegroup.hall_symbol, spacegroup_type.hall_symbol); strcpy(spacegroup.international, spacegroup_type.international); strcpy(spacegroup.international_long, spacegroup_type.international_full); strcpy(spacegroup.international_short, spacegroup_type.international_short); } else { spacegroup.number = 0; warning_print("spglib: Space group could not be found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); } ret: /* spacegroup.number = 0 when space group was not found. */ sym_free_symmetry(symmetry); return spacegroup; }
/* Return NULL if failed */ Symmetry * sym_alloc_symmetry(const int size) { Symmetry *symmetry; symmetry = NULL; if (size < 1) { return NULL; } if ((symmetry = (Symmetry*) malloc(sizeof(Symmetry))) == NULL) { warning_print("spglib: Memory could not be allocated "); return NULL; } symmetry->size = size; symmetry->rot = NULL; symmetry->trans = NULL; if ((symmetry->rot = (int (*)[3][3]) malloc(sizeof(int[3][3]) * size)) == NULL) { warning_print("spglib: Memory could not be allocated "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); free(symmetry); symmetry = NULL; return NULL; } if ((symmetry->trans = (double (*)[3]) malloc(sizeof(double[3]) * size)) == NULL) { warning_print("spglib: Memory could not be allocated "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); free(symmetry->rot); symmetry->rot = NULL; free(symmetry); symmetry = NULL; return NULL; } return symmetry; }
/* NULL is returned if faied */ Cell * cel_alloc_cell(const int size) { Cell *cell; int i, j; cell = NULL; if ((cell = (Cell*) malloc(sizeof(Cell))) == NULL) { warning_print("spglib: Memory could not be allocated."); return NULL; } for ( i = 0; i < 3; i++ ) { for ( j = 0; j < 3; j++ ) { cell->lattice[i][j] = 0; } } cell->size = size; if (size > 0) { if ((cell->types = (int *) malloc(sizeof(int) * size)) == NULL) { warning_print("spglib: Memory could not be allocated."); free(cell); cell = NULL; return NULL; } if ((cell->position = (double (*)[3]) malloc(sizeof(double[3]) * size)) == NULL) { warning_print("spglib: Memory could not be allocated."); free(cell->types); cell->types = NULL; free(cell); cell = NULL; return NULL; } } return cell; }
/* Return 0 if failed */ static int get_Delaunay_reduction(double red_lattice[3][3], SPGCONST double lattice[3][3], const double symprec) { int i, j; double volume, sum; double basis[4][3]; get_exteneded_basis(basis, lattice); sum = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 3; j++) { sum += basis[i][j] * basis[i][j]; } } while (1) { if (get_Delaunay_reduction_basis(basis, symprec)) { break; } } get_Delaunay_shortest_vectors(basis, symprec); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { red_lattice[i][j] = basis[j][i]; } } volume = mat_get_determinant_d3(red_lattice); if (mat_Dabs(volume) < symprec) { warning_print("spglib: Minimum lattice has no volume (line %d, %s).\n", __LINE__, __FILE__); goto err; } if (volume < 0) { /* Flip axes */ for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { red_lattice[i][j] = -red_lattice[i][j]; } } } return 1; err: return 0; }
static int get_pointgroup_class_table(int table[10], SPGCONST PointSymmetry * pointsym) { /* Look-up table */ /* Operation -6 -4 -3 -2 -1 1 2 3 4 6 */ /* Trace - 2 -1 0 1 -3 3 -1 0 1 2 */ /* Determinant -1 -1 -1 -1 -1 1 1 1 1 1 */ /* table[0] = -6 axis */ /* table[1] = -4 axis */ /* table[2] = -3 axis */ /* table[3] = -2 axis */ /* table[4] = -1 axis */ /* table[5] = 1 axis */ /* table[6] = 2 axis */ /* table[7] = 3 axis */ /* table[8] = 4 axis */ /* table[9] = 6 axis */ int i, rot_type; for (i = 0; i < 10; i++) { table[i] = 0; } for (i = 0; i < pointsym->size; i++) { rot_type = get_rotation_type(pointsym->rot[i]); if (rot_type == -1) { goto err; } else { table[rot_type]++; } } return 1; err: warning_print("spglib: No point group symbol found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); return 0; }
/* m = b^-1 a b */ int mat_get_similar_matrix_d3(double m[3][3], SPGCONST double a[3][3], SPGCONST double b[3][3], const double precision) { double c[3][3]; if (!mat_inverse_matrix_d3(c, b, precision)) { warning_print("spglib: No similar matrix due to 0 determinant.\n"); debug_print("No similar matrix due to 0 determinant.\n"); return 0; } mat_multiply_matrix_d3(m, a, b); mat_multiply_matrix_d3(m, c, m); return 1; }
/* 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 double * get_transpose(const double *M) { int i, j; double *M_T; M_T = NULL; if ((M_T = (double*)malloc(sizeof(double) * 9)) == NULL) { warning_print("niggli: Memory could not be allocated."); return NULL; } for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { M_T[i * 3 + j] = M[j * 3 + i]; } } return M_T; }
static int get_hall_number_local_iteration(double origin_shift[3], double conv_lattice[3][3], SPGCONST Cell * primitive, SPGCONST Symmetry * symmetry, const double symprec) { int attempt, pg_num, hall_number=0; double tolerance; Symmetry * sym_reduced; debug_print("get_hall_number_local_iteration:\n"); tolerance = symprec; for (attempt = 0; attempt < 100; attempt++) { tolerance *= REDUCE_RATE; debug_print(" Attempt %d tolerance = %f\n", attempt, tolerance); sym_reduced = sym_reduce_operation(primitive, symmetry, tolerance); pg_num = ptg_get_pointgroup_number(sym_reduced); if (pg_num > -1) { hall_number = get_hall_number_local(origin_shift, conv_lattice, primitive, sym_reduced, symprec); if (hall_number > 0) { sym_free_symmetry(sym_reduced); break; } } sym_free_symmetry(sym_reduced); } #ifdef SPGWARNING if (hall_number == 0) { warning_print("spglib: Iterative attempt with sym_reduce_operation to find Hall symbol failed.\n"); } #endif return hall_number; }
static int get_index_with_least_atoms(const Cell *cell) { int i, j, min, min_index; int *mapping; mapping = NULL; if ((mapping = (int *) malloc(sizeof(int) * cell->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return -1; } for (i = 0; i < cell->size; i++) { mapping[i] = 0; } for (i = 0; i < cell->size; i++) { for (j = 0; j < cell->size; j++) { if (cell->types[i] == cell->types[j]) { mapping[j]++; break; } } } min = mapping[0]; min_index = 0; for (i = 0; i < cell->size; i++) { if (min > mapping[i] && mapping[i] >0) { min = mapping[i]; min_index = i; } } free(mapping); mapping = NULL; return min_index; }
static double * multiply_matrices(const double *L, const double *R) { int i, j, k; double *M; M = NULL; if ((M = (double*)malloc(sizeof(double) * 9)) == NULL) { warning_print("niggli: Memory could not be allocated."); return NULL; } for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { M[i * 3 + j] = 0; for (k = 0; k < 3; k++) { M[i * 3 + j] += L[i * 3 + k] * R[k * 3 + j]; } } } return M; }
static int laue_one_axis(int axes[3], SPGCONST PointSymmetry * pointsym, const int rot_order) { int i, j, num_ortho_axis, det, is_found, tmpval; int axis_vec[3], tmp_axes[3]; int prop_rot[3][3], t_mat[3][3]; int ortho_axes[NUM_ROT_AXES]; debug_print("laue_one_axis with rot_order %d\n", rot_order); for (i = 0; i < pointsym->size; i++) { get_proper_rotation(prop_rot, pointsym->rot[i]); /* Search foud-fold rotation */ if (rot_order == 4) { if (mat_get_trace_i3(prop_rot) == 1) { /* The first axis */ axes[2] = get_rotation_axis(prop_rot); break; } } /* Search three-fold rotation */ if (rot_order == 3) { if (mat_get_trace_i3(prop_rot) == 0) { /* The first axis */ axes[2] = get_rotation_axis(prop_rot); break; } } } /* Candidates of the second axis */ num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, rot_order); if (! num_ortho_axis) { goto err; } tmp_axes[1] = -1; tmp_axes[2] = axes[2]; for (i = 0; i < num_ortho_axis; i++) { is_found = 0; tmp_axes[0] = ortho_axes[i]; mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[tmp_axes[0]]); for (j = 0; j < num_ortho_axis; j++) { is_found = is_exist_axis(axis_vec, ortho_axes[j]); if (is_found == 1) { tmp_axes[1] = ortho_axes[j]; break; } if (is_found == -1) { tmp_axes[1] = ortho_axes[j] + NUM_ROT_AXES; break; } } if (!is_found) { continue; } set_transformation_matrix(t_mat, tmp_axes); det = abs(mat_get_determinant_i3(t_mat)); if (det < 4) { /* to avoid F-center choice det=4 */ axes[0] = tmp_axes[0]; axes[1] = tmp_axes[1]; goto end; } } err: /* axes are not correctly found. */ warning_print("spglib: Secondary axis is not found."); warning_print("(line %d, %s).\n", __LINE__, __FILE__); return 0; end: set_transformation_matrix(t_mat, axes); if (mat_get_determinant_i3(t_mat) < 0) { tmpval = axes[0]; axes[0] = axes[1]; axes[1] = tmpval; } debug_print("axes[0] = %d\n", axes[0]); debug_print("axes[1] = %d\n", axes[1]); debug_print("axes[2] = %d\n", axes[2]); return 1; }
/* 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; }
/* Return NULL if failed */ 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; ir_rot = NULL; rot_reciprocal_q = NULL; is_all_ok = 0; num_rot = 0; if ((ir_rot = (int*)malloc(sizeof(int) * rot_reciprocal->size)) == NULL) { warning_print("spglib: Memory of ir_rot could not be allocated."); return NULL; } 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++; } } if ((rot_reciprocal_q = mat_alloc_MatINT(num_rot)) != NULL) { 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); ir_rot = NULL; return rot_reciprocal_q; }
/* Return NULL if failed */ static MatINT *get_point_group_reciprocal(const MatINT * rotations, const int is_time_reversal) { int i, j, num_rot; MatINT *rot_reciprocal, *rot_return; int *unique_rot; SPGCONST int inversion[3][3] = { {-1, 0, 0 }, { 0,-1, 0 }, { 0, 0,-1 } }; rot_reciprocal = NULL; rot_return = NULL; unique_rot = NULL; if (is_time_reversal) { if ((rot_reciprocal = mat_alloc_MatINT(rotations->size * 2)) == NULL) { return NULL; } } else { if ((rot_reciprocal = mat_alloc_MatINT(rotations->size)) == NULL) { return NULL; } } if ((unique_rot = (int*)malloc(sizeof(int) * rot_reciprocal->size)) == NULL) { warning_print("spglib: Memory of unique_rot could not be allocated."); mat_free_MatINT(rot_reciprocal); return NULL; } for (i = 0; i < rot_reciprocal->size; i++) { unique_rot[i] = -1; } for (i = 0; i < rotations->size; i++) { mat_transpose_matrix_i3(rot_reciprocal->mat[i], rotations->mat[i]); if (is_time_reversal) { mat_multiply_matrix_i3(rot_reciprocal->mat[rotations->size+i], inversion, rot_reciprocal->mat[i]); } } num_rot = 0; for (i = 0; i < rot_reciprocal->size; i++) { for (j = 0; j < num_rot; j++) { if (mat_check_identity_matrix_i3(rot_reciprocal->mat[unique_rot[j]], rot_reciprocal->mat[i])) { goto escape; } } unique_rot[num_rot] = i; num_rot++; escape: ; } if ((rot_return = mat_alloc_MatINT(num_rot)) != NULL) { for (i = 0; i < num_rot; i++) { mat_copy_matrix_i3(rot_return->mat[i], rot_reciprocal->mat[unique_rot[i]]); } } free(unique_rot); unique_rot = NULL; mat_free_MatINT(rot_reciprocal); rot_reciprocal = NULL; return rot_return; }
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; }
/* 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 NULL if failed */ static VecDBL * get_translation(SPGCONST int rot[3][3], SPGCONST Cell *cell, const double symprec, const int is_identity) { int i, j, k, min_atom_index, num_trans; int *is_found; double origin[3]; VecDBL *trans; debug_print("get_translation (tolerance = %f):\n", symprec); num_trans = 0; is_found = NULL; trans = NULL; #ifdef _OPENMP int num_min_type_atoms; int *min_type_atoms; double vec[3]; min_type_atoms = NULL; #endif if ((is_found = (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[i] = 0; } /* Look for the atom index with least number of atoms within same type */ min_atom_index = get_index_with_least_atoms(cell); if (min_atom_index == -1) { debug_print("spglib: get_index_with_least_atoms failed.\n"); goto ret; } /* Set min_atom_index as the origin to measure the distance between atoms. */ mat_multiply_matrix_vector_id3(origin, rot, cell->position[min_atom_index]); #ifdef _OPENMP if (cell->size < NUM_ATOMS_CRITERION_FOR_OPENMP) { num_trans = search_translation_part(is_found, cell, rot, min_atom_index, origin, symprec, is_identity); if (num_trans == 0) { goto ret; } } else { /* Collect indices of atoms with the type where the minimum number */ /* of atoms belong. */ if ((min_type_atoms = (int*) malloc(sizeof(int)*cell->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); goto ret; } num_min_type_atoms = 0; for (i = 0; i < cell->size; i++) { if (cell->types[i] == cell->types[min_atom_index]) { min_type_atoms[num_min_type_atoms] = i; num_min_type_atoms++; } } #pragma omp parallel for private(j, vec) for (i = 0; i < num_min_type_atoms; i++) { for (j = 0; j < 3; j++) { vec[j] = cell->position[min_type_atoms[i]][j] - origin[j]; } if (is_overlap_all_atoms(vec, rot, cell, symprec, is_identity)) { is_found[min_type_atoms[i]] = 1; } } free(min_type_atoms); min_type_atoms = NULL; for (i = 0; i < cell->size; i++) { num_trans += is_found[i]; } } #else num_trans = search_translation_part(is_found, cell, rot, min_atom_index, origin, symprec, is_identity); if (num_trans == 0) { goto ret; } #endif if ((trans = mat_alloc_VecDBL(num_trans)) == NULL) { goto ret; } k = 0; for (i = 0; i < cell->size; i++) { if (is_found[i]) { for (j = 0; j < 3; j++) { trans->vec[k][j] = cell->position[i][j] - origin[j]; } k++; } } ret: free(is_found); is_found = NULL; return trans; }