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; }
/* 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; }
/* If primitive could not be found, primitive->size = -1 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; /* 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 = cel_alloc_cell( cell->size / multi ); if ( ! lat_smallest_lattice_vector( primitive->lattice, prim_lattice, symprec ) ) { cel_free_cell( primitive ); goto not_found; } /* Fit atoms into new primitive cell */ if ( ! trim_cell( primitive, mapping_table, cell, symprec ) ) { cel_free_cell( primitive ); goto not_found; } debug_print("Original cell lattice.\n"); debug_print_matrix_d3(cell->lattice); debug_print("Found primitive lattice after choosing least axes.\n"); debug_print_matrix_d3(primitive->lattice); debug_print("Number of atoms in primitive cell: %d\n", primitive->size); debug_print("Volume: original %f --> primitive %f\n", mat_get_determinant_d3(cell->lattice), mat_get_determinant_d3(primitive->lattice)); /* found */ return primitive; not_found: primitive = cel_alloc_cell( -1 ); warning_print("spglib: Primitive cell could not found "); warning_print("(line %d, %s).\n", __LINE__, __FILE__); return primitive; }
static Cell * refine_cell(SPGCONST Cell * cell, const double symprec) { int *wyckoffs, *equiv_atoms; double tolerance; Cell *primitive, *bravais, *conv_prim; Symmetry *conv_sym; Spacegroup spacegroup; debug_print("refine_cell:\n"); primitive = prm_get_primitive(cell, symprec); if (primitive->size == 0) { cel_free_cell(primitive); bravais = cel_alloc_cell(0); goto end; } tolerance = prm_get_current_tolerance(); spacegroup = spa_get_spacegroup_with_primitive(primitive, tolerance); wyckoffs = (int*)malloc(sizeof(int) * primitive->size); equiv_atoms = (int*)malloc(sizeof(int) * primitive->size); conv_prim = get_bravais_exact_positions_and_lattice(wyckoffs, equiv_atoms, &spacegroup, primitive, tolerance); free(equiv_atoms); equiv_atoms = NULL; free(wyckoffs); wyckoffs = NULL; conv_sym = get_db_symmetry(spacegroup.hall_number); bravais = expand_positions(conv_prim, conv_sym); debug_print("primitive cell in refine_cell:\n"); debug_print_matrix_d3(primitive->lattice); debug_print("conventional lattice in refine_cell:\n"); debug_print_matrix_d3(conv_prim->lattice); debug_print("bravais lattice in refine_cell:\n"); debug_print_matrix_d3(bravais->lattice); cel_free_cell(conv_prim); sym_free_symmetry(conv_sym); cel_free_cell(primitive); end: /* Return bravais->size = 0, if the bravais could not be found. */ return bravais; }
static Centering get_transformation_matrix( double trans_mat[3][3], SPGCONST Symmetry * symmetry ) { int pg_num; double correction_mat[3][3]; Centering centering; Pointgroup pointgroup; pg_num = ptg_get_pointgroup_number( symmetry ); pointgroup = ptg_get_pointgroup( pg_num ); ptg_get_transformation_matrix( &pointgroup, symmetry ); /* Centering is not determined only from symmetry operations */ /* sometimes. Therefore centering and transformation matrix are */ /* related. */ centering = lat_get_centering( correction_mat, pointgroup.transform_mat, pointgroup.laue ); mat_multiply_matrix_id3( trans_mat, pointgroup.transform_mat, correction_mat ); debug_print("correction matrix\n"); debug_print_matrix_d3( correction_mat ); return centering; }
static void set_monocli(double lattice[3][3], SPGCONST double metric[3][3]) { /* Lattice is expected to be C centring */ double a, b, c, beta; debug_print("set_monocli:\n"); debug_print_matrix_d3(metric); a = sqrt(metric[0][0]); b = sqrt(metric[1][1]); c = sqrt(metric[2][2]); lattice[1][1] = b; lattice[2][2] = c; beta = acos(metric[0][2] / a / c); lattice[2][0] = a * cos(beta); lattice[0][0] = a * sin(beta); debug_print("beta %f\n", beta); debug_print_matrix_d3(lattice); }
static void get_conventional_lattice(double lattice[3][3], SPGCONST Spacegroup *spacegroup) { int i, j; double metric[3][3]; Pointgroup pointgroup; pointgroup = ptg_get_pointgroup(spacegroup->pointgroup_number); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { lattice[i][j] = 0; } } mat_get_metric(metric, spacegroup->bravais_lattice); debug_print("bravais lattice\n"); debug_print_matrix_d3(spacegroup->bravais_lattice); debug_print("%s\n", spacegroup->setting); switch (pointgroup.holohedry) { case TRICLI: set_tricli(lattice, metric); break; case MONOCLI: /* b-axis is the unique axis. */ set_monocli(lattice, metric); break; case ORTHO: set_ortho(lattice, metric); break; case TETRA: set_tetra(lattice, metric); break; case TRIGO: if (spacegroup->setting[0] == 'R') { set_rhomb(lattice, metric); } else { set_trigo(lattice, metric); } break; case HEXA: set_trigo(lattice, metric); break; case CUBIC: set_cubic(lattice, metric); break; case HOLOHEDRY_NONE: break; } }
Symmetry * sym_get_operation( SPGCONST Cell *cell, const double symprec ) { int i, j, num_sym; MatINT *rot; VecDBL *trans; Symmetry *symmetry; rot = mat_alloc_MatINT( cell->size * 48 ); trans = mat_alloc_VecDBL( cell->size * 48 ); num_sym = get_operation( rot->mat, trans->vec, cell, symprec ); #ifdef DEBUG debug_print("*** get_symmetry (found symmetry operations) *** \n"); debug_print("Lattice \n"); debug_print_matrix_d3(cell->lattice); for ( i = 0; i < num_sym; i++ ) { debug_print("--- %d ---\n", i + 1); debug_print_matrix_i3(rot->mat[i]); debug_print("%f %f %f\n", trans->vec[i][0], trans->vec[i][1], trans->vec[i][2]); } #endif symmetry = sym_alloc_symmetry( num_sym ); for ( i = 0; i < num_sym; i++ ) { mat_copy_matrix_i3(symmetry->rot[i], rot->mat[i]); for (j = 0; j < 3; j++) symmetry->trans[i][j] = trans->vec[i][j]; } mat_free_MatINT( rot ); mat_free_VecDBL( trans ); return symmetry; }
static 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)); debug_print("initial volume: %f\n", initial_volume); /* 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 ) { debug_print("temporary volume of primitive cell: %f\n", volume ); debug_print("volume of original cell: %f\n", initial_volume ); debug_print("multi and calculated multi: %d, %d\n", size-2, mat_Nint( initial_volume / volume ) ); 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 ); debug_print("Oritinal relative_lattice\n"); debug_print_matrix_d3( relative_lattice ); debug_print("Cleaned relative_lattice\n"); debug_print_matrix_d3( relative_lattice ); debug_print("Primitive lattice\n"); debug_print_matrix_d3( prim_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; }