static PointSymmetry get_lattice_symmetry(SPGCONST Cell *cell, const double symprec) { int i, j, k, num_sym; int axes[3][3]; double lattice[3][3], min_lattice[3][3]; double metric[3][3], metric_orig[3][3]; PointSymmetry lattice_sym; debug_print("get_lattice_symmetry:\n"); if (! lat_smallest_lattice_vector(min_lattice, cell->lattice, symprec)) { goto err; } mat_get_metric(metric_orig, min_lattice); num_sym = 0; for (i = 0; i < 26; i++) { for (j = 0; j < 26; j++) { for (k = 0; k < 26; k++) { set_axes(axes, i, j, k); if (! ((mat_get_determinant_i3(axes) == 1) || (mat_get_determinant_i3(axes) == -1))) { continue; } mat_multiply_matrix_di3(lattice, min_lattice, axes); mat_get_metric(metric, lattice); if (is_identity_metric(metric, metric_orig, symprec)) { mat_copy_matrix_i3(lattice_sym.rot[num_sym], axes); num_sym++; } if (num_sym > 48) { warning_print("spglib: Too many lattice symmetries was found.\n"); warning_print(" Tolerance may be too large "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); goto err; } } } } lattice_sym.size = num_sym; return transform_pointsymmetry(&lattice_sym, cell->lattice, min_lattice); err: lattice_sym.size = 0; return lattice_sym; }
static void sort_axes(int axes[3]) { int axis; int t_mat[3][3]; if (axes[1] > axes[2]) { axis = axes[1]; axes[1] = axes[2]; axes[2] = axis; } if (axes[0] > axes[1]) { axis = axes[0]; axes[0] = axes[1]; axes[1] = axis; } if (axes[1] > axes[2]) { axis = axes[1]; axes[1] = axes[2]; axes[2] = axis; } set_transformation_matrix(t_mat, axes); if (mat_get_determinant_i3(t_mat) < 0) { axis = axes[1]; axes[1] = axes[2]; axes[2] = axis; } }
static int lauem3m( int axes[3], const Symmetry * symmetry ) { int i, count, axis, tmpval; int prop_rot[3][3], t_mat[3][3]; for ( i = 0; i < 3; i++ ) { axes[i] = -1; } count = 0; for ( i = 0; i < symmetry->size; i++ ) { get_proper_rotation( prop_rot, symmetry->rot[i] ); /* Search four-fold rotation */ if ( ! ( mat_get_trace_i3( prop_rot ) == 1 ) ) { continue; } axis = get_rotation_axis( prop_rot ); if ( ! ( ( axis == axes[0] ) || ( axis == axes[1] ) || ( axis == axes[2] ) ) ) { axes[count] = axis; count++; } } get_transform_matrix( t_mat, axes ); if ( mat_get_determinant_i3( t_mat ) < 0 ) { tmpval = axes[0]; axes[0] = axes[1]; axes[1] = tmpval; } return 1; }
static int laue4m(int axes[3], SPGCONST PointSymmetry * pointsym) { int i, num_ortho_axis, norm, min_norm, is_found, tmpval; int axis_vec[3]; int prop_rot[3][3], t_mat[3][3]; int ortho_axes[NUM_ROT_AXES]; for (i = 0; i < pointsym->size; i++) { get_proper_rotation(prop_rot, pointsym->rot[i]); /* Search foud-fold rotation */ if ( mat_get_trace_i3(prop_rot) == 1) { /* The first axis */ axes[2] = get_rotation_axis(prop_rot); break; } } /* The second axis */ num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, 4); if (! num_ortho_axis) { goto err; } min_norm = 8; is_found = 0; for (i = 0; i < num_ortho_axis; i++) { norm = mat_norm_squared_i3(rot_axes[ortho_axes[i]]); if (norm < min_norm) { min_norm = norm; axes[0] = ortho_axes[i]; is_found = 1; } } if (! is_found) { goto err; } /* The third axis */ mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]); is_found = 0; for (i = 0; i < NUM_ROT_AXES; i++) { if (is_exist_axis(axis_vec, i)) { is_found = 1; axes[1] = i; break; } } if (! is_found) { goto err; } set_transformation_matrix(t_mat, axes); if (mat_get_determinant_i3(t_mat) < 0) { tmpval = axes[0]; axes[0] = axes[1]; axes[1] = tmpval; } return 1; err: return 0; }
static void get_proper_rotation(int prop_rot[3][3], SPGCONST int rot[3][3]) { if (mat_get_determinant_i3(rot) == -1) { mat_multiply_matrix_i3(prop_rot, inversion, rot); } else { mat_copy_matrix_i3(prop_rot, rot); } }
static Centering get_centering(double correction_mat[3][3], SPGCONST int transform_mat[3][3], const Laue laue) { int det; double trans_corr_mat[3][3]; Centering centering; mat_copy_matrix_d3(correction_mat, identity); det = abs(mat_get_determinant_i3(transform_mat)); debug_print("laue class: %d\n", laue); debug_print("multiplicity: %d\n", det); if (det == 1) { centering = NO_CENTER; } if (det == 2) { centering = get_base_center(transform_mat); if (centering == A_FACE) { if (laue == LAUE2M) { debug_print("Monocli A to C\n"); mat_copy_matrix_d3(correction_mat, monocli_a2c); } else { mat_copy_matrix_d3(correction_mat, a2c); } centering = C_FACE; } if (centering == B_FACE) { mat_copy_matrix_d3(correction_mat, b2c); centering = C_FACE; } if (laue == LAUE2M && centering == BODY) { debug_print("Monocli I to C\n"); mat_copy_matrix_d3(correction_mat, monocli_i2c); centering = C_FACE; } } if (det == 3) { centering = NO_CENTER; mat_multiply_matrix_id3(trans_corr_mat, transform_mat, rhombo_obverse); if (mat_is_int_matrix(trans_corr_mat, INT_PREC)) { mat_copy_matrix_d3(correction_mat, rhombo_obverse); debug_print("R-center observe setting\n"); debug_print_matrix_d3(trans_corr_mat); } mat_multiply_matrix_id3(trans_corr_mat, transform_mat, rhomb_reverse); if (mat_is_int_matrix(trans_corr_mat, INT_PREC)) { mat_copy_matrix_d3(correction_mat, rhomb_reverse); debug_print("R-center reverse setting\n"); debug_print_matrix_d3(trans_corr_mat); } } if (det == 4) { centering = FACE; } return centering; }
static int get_rotation_type(SPGCONST int rot[3][3]) { int rot_type; if (mat_get_determinant_i3(rot) == -1) { switch (mat_get_trace_i3(rot)) { case -2: /* -6 */ rot_type = 0; break; case -1: /* -4 */ rot_type = 1; break; case 0: /* -3 */ rot_type = 2; break; case 1: /* -2 */ rot_type = 3; break; case -3: /* -1 */ rot_type = 4; break; default: rot_type = -1; break; } } else { switch (mat_get_trace_i3(rot)) { case 3: /* 1 */ rot_type = 5; break; case -1: /* 2 */ rot_type = 6; break; case 0: /* 3 */ rot_type = 7; break; case 1: /* 4 */ rot_type = 8; break; case 2: /* 6 */ rot_type = 9; break; default: rot_type = -1; break; } } return rot_type; }
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; }
static int laue3m(int axes[3], SPGCONST PointSymmetry * pointsym) { int i, is_found, tmpval, axis; int prop_rot[3][3], prop_rot2[3][3], t_mat[3][3]; int axis_vec[3]; for (i = 0; i < pointsym->size; i++) { get_proper_rotation(prop_rot, pointsym->rot[i]); /* Search three-fold rotation */ if (mat_get_trace_i3(prop_rot) == 0) { /* The first axis */ axes[2] = get_rotation_axis(prop_rot); debug_print("laue3m prop_rot\n"); debug_print_matrix_i3(prop_rot); break; } } is_found = 0; for (i = 0; i < pointsym->size; i++) { get_proper_rotation(prop_rot2, pointsym->rot[i]); /* Search two-fold rotation */ if (! (mat_get_trace_i3(prop_rot2) == -1)) { continue; } /* The second axis */ axis = get_rotation_axis(prop_rot2); if (! (axis == axes[2])) { axes[0] = axis; is_found = 1; break; } } if (! is_found) { goto err; } /* The third axis */ mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]); is_found = 0; for (i = 0; i < NUM_ROT_AXES; i++) { is_found = is_exist_axis(axis_vec, i); if (is_found == 1) { axes[1] = i; break; } if (is_found == -1) { axes[1] = i + NUM_ROT_AXES; break; } } if (! is_found) { goto err; } set_transformation_matrix(t_mat, axes); if (mat_get_determinant_i3(t_mat) < 0) { tmpval = axes[0]; axes[0] = axes[1]; axes[1] = tmpval; } return 1; err: return 0; }
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; }
static int laue_one_axis( int axes[3], const Symmetry * symmetry, const int rot_order ) { int i, j, num_ortho_axis, det, min_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]; for ( i = 0; i < symmetry->size; i++ ) { get_proper_rotation( prop_rot, symmetry->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[2] = axes[2]; min_det = 4; is_found = 0; for ( i = 0; i < num_ortho_axis; i++ ) { 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; } } get_transform_matrix( t_mat, tmp_axes ); det = mat_get_determinant_i3( t_mat ); if ( det < 0 ) { det = -det; } if ( det < min_det ) { min_det = det; axes[0] = tmp_axes[0]; axes[1] = tmp_axes[1]; } } if ( ! is_found ) { goto err; } get_transform_matrix( t_mat, axes ); if ( mat_get_determinant_i3( t_mat ) < 0 ) { tmpval = axes[0]; axes[0] = axes[1]; axes[1] = tmpval; } return 1; err: return 0; }
static int laue4mmm( int axes[3], const Symmetry * symmetry ) { int i, is_found, tmpval, axis; int prop_rot[3][3], prop_rot2[3][3], t_mat[3][3]; int axis_vec[3]; for ( i = 0; i < symmetry->size; i++ ) { get_proper_rotation( prop_rot, symmetry->rot[i] ); /* Search foud-fold rotation */ if ( mat_get_trace_i3( prop_rot ) == 1 ) { /* The first axis */ axes[2] = get_rotation_axis( prop_rot ); break; } } is_found = 0; for ( i = 0; i < symmetry->size; i++ ) { get_proper_rotation( prop_rot2, symmetry->rot[i] ); /* Search two-fold rotation */ if ( ! ( mat_get_trace_i3( prop_rot2 ) == -1 ) ) { continue; } /* The second axis */ axis = get_rotation_axis( prop_rot2 ); if ( ! ( axis == axes[2] ) ) { axes[0] = axis; is_found = 1; break; } } if ( ! is_found ) { goto err; } /* The third axis */ mat_multiply_matrix_vector_i3( axis_vec, prop_rot, rot_axes[axes[0]] ); is_found = 0; for ( i = 0; i < NUM_ROT_AXES; i++ ) { if ( is_exist_axis( axis_vec, i ) ) { is_found = 1; axes[1] = i; break; } } if ( ! is_found ) { goto err; } get_transform_matrix( t_mat, axes ); if ( mat_get_determinant_i3( t_mat ) < 0 ) { tmpval = axes[0]; axes[0] = axes[1]; axes[1] = tmpval; } return 1; err: return 0; }
static int laue2m( int axes[3], const Symmetry * symmetry ) { int i, num_ortho_axis, norm, min_norm, is_found, tmpval; int prop_rot[3][3], t_mat[3][3]; int ortho_axes[NUM_ROT_AXES]; for ( i = 0; i < symmetry->size; i++ ) { get_proper_rotation( prop_rot, symmetry->rot[i] ); /* Search two-fold rotation */ if ( ! ( mat_get_trace_i3( prop_rot ) == -1 ) ) { continue; } /* The first axis */ axes[1] = get_rotation_axis( prop_rot ); break; } /* The second axis */ num_ortho_axis = get_orthogonal_axis( ortho_axes, prop_rot, 2 ); if ( ! num_ortho_axis ) { goto err; } min_norm = 8; is_found = 0; for ( i = 0; i < num_ortho_axis; i++ ) { norm = mat_norm_squared_i3( rot_axes[ortho_axes[i]] ); if ( norm < min_norm ) { min_norm = norm; axes[0] = ortho_axes[i]; is_found = 1; } } if ( ! is_found ) { goto err; } /* The third axis */ min_norm = 8; is_found = 0; for ( i = 0; i < num_ortho_axis; i++ ) { norm = mat_norm_squared_i3( rot_axes[ortho_axes[i]] ); if ( norm < min_norm && ( ! ( ortho_axes[i] == axes[0] ) ) ) { min_norm = norm; axes[2] = ortho_axes[i]; is_found = 1; } } if ( ! is_found ) { goto err; } get_transform_matrix( t_mat, axes ); if ( mat_get_determinant_i3( t_mat ) < 0 ) { tmpval = axes[0]; axes[0] = axes[2]; axes[2] = tmpval; } return 1; err: return 0; }
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 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; }
/* Return CENTERING_ERROR if failed */ static Centering get_centering(double correction_mat[3][3], SPGCONST int transform_mat[3][3], const Laue laue) { int det; double trans_corr_mat[3][3]; Centering centering; mat_copy_matrix_d3(correction_mat, identity); det = abs(mat_get_determinant_i3(transform_mat)); debug_print("laue class: %d\n", laue); debug_print("multiplicity: %d\n", det); switch (det) { case 1: centering = PRIMITIVE; break; case 2: centering = get_base_center(transform_mat); if (centering == A_FACE) { if (laue == LAUE2M) { debug_print("Monocli A to C\n"); mat_copy_matrix_d3(correction_mat, monocli_a2c); } else { mat_copy_matrix_d3(correction_mat, a2c); } centering = C_FACE; } if (centering == B_FACE) { mat_copy_matrix_d3(correction_mat, b2c); centering = C_FACE; } if (laue == LAUE2M && centering == BODY) { debug_print("Monocli I to C\n"); mat_copy_matrix_d3(correction_mat, monocli_i2c); centering = C_FACE; } break; case 3: /* hP (a=b) but not hR (a=b=c) */ centering = R_CENTER; mat_multiply_matrix_id3(trans_corr_mat, transform_mat, rhombo_obverse); if (mat_is_int_matrix(trans_corr_mat, INT_PREC)) { mat_copy_matrix_d3(correction_mat, rhombo_obverse); debug_print("R-center observe setting\n"); debug_print_matrix_d3(trans_corr_mat); } mat_multiply_matrix_id3(trans_corr_mat, transform_mat, rhomb_reverse); if (mat_is_int_matrix(trans_corr_mat, INT_PREC)) { mat_copy_matrix_d3(correction_mat, rhomb_reverse); debug_print("R-center reverse setting\n"); debug_print_matrix_d3(trans_corr_mat); } break; case 4: centering = FACE; break; default: centering = CENTERING_ERROR; break; } return centering; }