static Symmetry * reduce_operation(SPGCONST Cell * cell, SPGCONST Symmetry * symmetry, const double symprec) { int i, j, num_sym; Symmetry * sym_reduced; PointSymmetry point_symmetry; MatINT *rot; VecDBL *trans; debug_print("reduce_operation:\n"); point_symmetry = get_lattice_symmetry(cell, symprec); rot = mat_alloc_MatINT(symmetry->size); trans = mat_alloc_VecDBL(symmetry->size); num_sym = 0; for (i = 0; i < point_symmetry.size; i++) { for (j = 0; j < symmetry->size; j++) { if (mat_check_identity_matrix_i3(point_symmetry.rot[i], symmetry->rot[j])) { if (is_overlap_all_atoms(symmetry->trans[j], symmetry->rot[j], cell, symprec, 0)) { mat_copy_matrix_i3(rot->mat[num_sym], symmetry->rot[j]); mat_copy_vector_d3(trans->vec[num_sym], symmetry->trans[j]); num_sym++; } } } } sym_reduced = sym_alloc_symmetry(num_sym); for (i = 0; i < num_sym; i++) { mat_copy_matrix_i3(sym_reduced->rot[i], rot->mat[i]); mat_copy_vector_d3(sym_reduced->trans[i], trans->vec[i]); } mat_free_MatINT(rot); mat_free_VecDBL(trans); debug_print(" num_sym %d -> %d\n", symmetry->size, num_sym); return sym_reduced; }
/* Only the atoms corresponding to those in primitive are returned. */ static Cell * get_bravais_exact_positions_and_lattice(int * wyckoffs, int * equiv_atoms, SPGCONST Spacegroup *spacegroup, SPGCONST Cell * primitive, const double symprec) { int i; Symmetry *conv_sym; Cell *bravais; VecDBL *exact_positions; /* Positions of primitive atoms are represented wrt Bravais lattice */ bravais = get_conventional_primitive(spacegroup, primitive); /* Symmetries in database (wrt Bravais lattice) */ conv_sym = get_db_symmetry(spacegroup->hall_number); /* Lattice vectors are set. */ get_conventional_lattice(bravais->lattice, spacegroup->holohedry, spacegroup->bravais_lattice); /* Symmetrize atomic positions of conventional unit cell */ exact_positions = ssm_get_exact_positions(wyckoffs, equiv_atoms, bravais, conv_sym, spacegroup->hall_number, symprec); sym_free_symmetry(conv_sym); if (exact_positions->size > 0) { for (i = 0; i < bravais->size; i++) { mat_copy_vector_d3(bravais->position[i], exact_positions->vec[i]); } } else { cel_free_cell(bravais); bravais = cel_alloc_cell(0); } mat_free_VecDBL(exact_positions); return bravais; }
int spg_find_primitive( double lattice[3][3], double position[][3], int types[], const int num_atom, const double symprec ) { int i, j, num_prim_atom=0; int *mapping_table; Cell *cell, *primitive; VecDBL *pure_trans; cell = cel_alloc_cell( num_atom ); cel_set_cell( cell, lattice, position, types ); pure_trans = sym_get_pure_translation( cell, symprec ); /* find primitive cell */ if ( pure_trans->size > 1 ) { mapping_table = (int*) malloc( sizeof(int) * cell->size ); primitive = prm_get_primitive( mapping_table, cell, pure_trans, symprec ); free( mapping_table ); mapping_table = NULL; num_prim_atom = primitive->size; if ( num_prim_atom < num_atom && num_prim_atom > 0 ) { mat_copy_matrix_d3( lattice, primitive->lattice ); for ( i = 0; i < primitive->size; i++ ) { types[i] = primitive->types[i]; for (j=0; j<3; j++) { position[i][j] = primitive->position[i][j]; } } } cel_free_cell( primitive ); } else { num_prim_atom = 0; } mat_free_VecDBL( pure_trans ); cel_free_cell( cell ); return num_prim_atom; }
static Symmetry * get_space_group_operations(SPGCONST PointSymmetry *lattice_sym, SPGCONST Cell *cell, const double symprec) { int i, j, num_sym, total_num_sym; VecDBL **trans; Symmetry *symmetry; debug_print("get_space_group_operations:\n"); trans = (VecDBL**) malloc(sizeof(VecDBL*) * lattice_sym->size); total_num_sym = 0; for (i = 0; i < lattice_sym->size; i++) { trans[i] = get_translation(lattice_sym->rot[i], cell, symprec, 0); total_num_sym += trans[i]->size; } symmetry = sym_alloc_symmetry(total_num_sym); num_sym = 0; for (i = 0; i < lattice_sym->size; i++) { 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; } for (i = 0; i < lattice_sym->size; i++) { mat_free_VecDBL(trans[i]); } free(trans); trans = NULL; return symmetry; }
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; }
/* was not a primitive cell. */ static int get_operation( int rot[][3][3], double trans[][3], SPGCONST Cell *cell, const double symprec ) { int num_sym; int multi; int *mapping_table; PointSymmetry lattice_sym; Cell *primitive; VecDBL *pure_trans; pure_trans = sym_get_pure_translation(cell, symprec); multi = pure_trans->size; /* Lattice symmetry for input cell*/ lattice_sym = get_lattice_symmetry( cell, symprec ); if ( lattice_sym.size == 0 ) { goto err; } /* Obtain primitive cell */ if( multi > 1 ) { mapping_table = (int*) malloc( sizeof(int) * cell->size ); primitive = prm_get_primitive( mapping_table, cell, pure_trans, symprec ); free( mapping_table ); mapping_table = NULL; if ( primitive->size < 1 ) { goto err; } lattice_sym = transform_pointsymmetry( &lattice_sym, primitive->lattice, cell->lattice ); if ( lattice_sym.size == 0 ) { goto err; } } else { primitive = cell; } /* Symmetry operation search for primitive cell */ num_sym = get_space_group_operation( rot, trans, &lattice_sym, primitive, symprec ); /* Recover symmetry operation for the input structure (overwritten) */ if( multi > 1 ) { num_sym = get_operation_supercell( rot, trans, num_sym, pure_trans, cell, primitive ); cel_free_cell( primitive ); if ( num_sym == 0 ) { goto err; } } mat_free_VecDBL( pure_trans ); return num_sym; err: mat_free_VecDBL( pure_trans ); return 0; }
/* Return NULL if failed */ static Primitive * get_primitive(SPGCONST Cell * cell, const double symprec) { int i, attempt, is_found = 0; double tolerance; Primitive *primitive; VecDBL * pure_trans; debug_print("get_primitive (tolerance = %f):\n", symprec); primitive = NULL; pure_trans = NULL; if ((primitive = prm_alloc_primitive(cell->size)) == NULL) { return NULL; } tolerance = symprec; for (attempt = 0; attempt < 100; attempt++) { if ((pure_trans = sym_get_pure_translation(cell, tolerance)) == NULL) { printf("***** hoge ******\n"); goto cont; } if (pure_trans->size == 1) { if ((primitive->cell = get_cell_with_smallest_lattice(cell, tolerance)) == NULL) { mat_free_VecDBL(pure_trans); goto cont; } for (i = 0; i < cell->size; i++) { primitive->mapping_table[i] = i; } } else { if ((primitive->cell = get_primitive_cell(primitive->mapping_table, cell, pure_trans, tolerance)) == NULL) { mat_free_VecDBL(pure_trans); goto cont; } } is_found = 1; break; cont: tolerance *= REDUCE_RATE; warning_print("spglib: Reduce tolerance to %f ", tolerance); warning_print("(line %d, %s).\n", __LINE__, __FILE__); } mat_free_VecDBL(pure_trans); if (is_found) { primitive->tolerance = tolerance; } else { prm_free_primitive(primitive); } return primitive; }
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 int multiplicity, const double symprec) { int i, j, k, l, num_trans, size_sym_orig; Symmetry *symmetry, *t_sym; double inv_tmat[3][3], tmp_mat[3][3], tmp_rot_d[3][3], tmp_lat_d[3][3], tmp_lat_i[3][3]; int tmp_rot_i[3][3]; VecDBL *pure_trans, *lattice_trans; mat_cast_matrix_3i_to_3d(tmp_mat, t_mat); mat_inverse_matrix_d3(inv_tmat, tmp_mat, symprec); /* transformed lattice points */ lattice_trans = mat_alloc_VecDBL(frame[0]*frame[1]*frame[2]); num_trans = 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[num_trans][0] = i; lattice_trans->vec[num_trans][1] = j; lattice_trans->vec[num_trans][2] = k; mat_multiply_matrix_vector_d3(lattice_trans->vec[num_trans], inv_tmat, lattice_trans->vec[num_trans]); for (l = 0; l < 3; l++) { /* t' = T^-1*t */ lattice_trans->vec[num_trans][l] = \ mat_Dmod1(lattice_trans->vec[num_trans][l]); } num_trans++; } } } /* transformed symmetry operations of primitive cell */ t_sym = sym_alloc_symmetry(prim_sym->size); size_sym_orig = 0; for (i = 0; i < prim_sym->size; i++) { /* R' = T^-1*R*T */ mat_multiply_matrix_di3(tmp_mat, inv_tmat, prim_sym->rot[i]); mat_multiply_matrix_di3(tmp_rot_d, tmp_mat, t_mat); mat_cast_matrix_3d_to_3i(tmp_rot_i, tmp_rot_d); mat_multiply_matrix_di3(tmp_lat_i, lattice, tmp_rot_i); mat_multiply_matrix_d3(tmp_lat_d, lattice, tmp_rot_d); if (mat_check_identity_matrix_d3(tmp_lat_i, tmp_lat_d, symprec)) { mat_copy_matrix_i3(t_sym->rot[size_sym_orig], tmp_rot_i); /* t' = T^-1*t */ mat_multiply_matrix_vector_d3(t_sym->trans[size_sym_orig], inv_tmat, prim_sym->trans[i]); size_sym_orig++; } } /* reduce lattice points */ pure_trans = reduce_lattice_points(lattice, lattice_trans, symprec); if (! (pure_trans->size == multiplicity)) { symmetry = sym_alloc_symmetry(0); goto ret; } /* copy symmetry operations upon lattice points */ symmetry = sym_alloc_symmetry(pure_trans->size * size_sym_orig); for (i = 0; i < pure_trans->size; i++) { for (j = 0; j < size_sym_orig; j++) { mat_copy_matrix_i3(symmetry->rot[size_sym_orig * i + j], t_sym->rot[j]); mat_copy_vector_d3(symmetry->trans[size_sym_orig * i + j], t_sym->trans[j]); for (k = 0; k < 3; k++) { symmetry->trans[size_sym_orig * i + j][k] += pure_trans->vec[i][k]; symmetry->trans[size_sym_orig * i + j][k] = \ mat_Dmod1(symmetry->trans[size_sym_orig * i + j][k]); } } } ret: mat_free_VecDBL(lattice_trans); mat_free_VecDBL(pure_trans); sym_free_symmetry(t_sym); return symmetry; }
static Symmetry * get_primitive_db_symmetry(SPGCONST double t_mat[3][3], const Symmetry *conv_sym) { 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 = NULL; t_prim = NULL; prim_sym = NULL; if ((r_prim = mat_alloc_MatINT(conv_sym->size)) == NULL) { return NULL; } if ((t_prim = mat_alloc_VecDBL(conv_sym->size)) == NULL) { mat_free_MatINT(r_prim); r_prim = NULL; return NULL; } mat_inverse_matrix_d3(inv_mat, t_mat, 0); 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: ; } if ((prim_sym = sym_alloc_symmetry(num_op)) == NULL) { goto ret; } 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] = mat_Dmod1(t_prim->vec[i][j]); } } ret: mat_free_MatINT(r_prim); r_prim = NULL; mat_free_VecDBL(t_prim); t_prim = NULL; return prim_sym; }
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 Symmetry * reduce_operation(SPGCONST Cell * primitive, SPGCONST Symmetry * symmetry, const double symprec, const double angle_symprec) { int i, j, num_sym; Symmetry * sym_reduced; PointSymmetry point_symmetry; MatINT *rot; VecDBL *trans; debug_print("reduce_operation:\n"); sym_reduced = NULL; rot = NULL; trans = NULL; point_symmetry = get_lattice_symmetry(primitive->lattice, symprec, angle_symprec); if (point_symmetry.size == 0) { return NULL; } if ((rot = mat_alloc_MatINT(symmetry->size)) == NULL) { return NULL; } if ((trans = mat_alloc_VecDBL(symmetry->size)) == NULL) { mat_free_MatINT(rot); rot = NULL; return NULL; } num_sym = 0; for (i = 0; i < point_symmetry.size; i++) { for (j = 0; j < symmetry->size; j++) { if (mat_check_identity_matrix_i3(point_symmetry.rot[i], symmetry->rot[j])) { if (is_overlap_all_atoms(symmetry->trans[j], symmetry->rot[j], primitive, symprec, 0)) { mat_copy_matrix_i3(rot->mat[num_sym], symmetry->rot[j]); mat_copy_vector_d3(trans->vec[num_sym], symmetry->trans[j]); num_sym++; } } } } if ((sym_reduced = sym_alloc_symmetry(num_sym)) != NULL) { for (i = 0; i < num_sym; i++) { mat_copy_matrix_i3(sym_reduced->rot[i], rot->mat[i]); mat_copy_vector_d3(sym_reduced->trans[i], trans->vec[i]); } } mat_free_MatINT(rot); rot = NULL; mat_free_VecDBL(trans); trans = NULL; return sym_reduced; }
/* 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; }
SpglibDataset * spg_get_dataset( SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const int num_atom, const double symprec ) { int i, j; int *mapping_table, *wyckoffs, *equiv_atoms, *equiv_atoms_prim; Spacegroup spacegroup; SpglibDataset *dataset; Cell *cell, *primitive; double inv_mat[3][3]; Symmetry *symmetry; VecDBL *pure_trans; dataset = (SpglibDataset*) malloc( sizeof( SpglibDataset ) ); cell = cel_alloc_cell( num_atom ); cel_set_cell( cell, lattice, position, types ); pure_trans = sym_get_pure_translation( cell, symprec ); mapping_table = (int*) malloc( sizeof(int) * cell->size ); primitive = prm_get_primitive( mapping_table, cell, pure_trans, symprec ); mat_free_VecDBL( pure_trans ); spacegroup = spa_get_spacegroup_with_primitive( primitive, symprec ); /* Spacegroup type, transformation matrix, origin shift */ if ( spacegroup.number > 0 ) { dataset->spacegroup_number = spacegroup.number; strcpy( dataset->international_symbol, spacegroup.international_short); strcpy( dataset->hall_symbol, spacegroup.hall_symbol); mat_inverse_matrix_d3( inv_mat, lattice, symprec ); mat_multiply_matrix_d3( dataset->transformation_matrix, inv_mat, spacegroup.bravais_lattice ); mat_copy_vector_d3( dataset->origin_shift, spacegroup.origin_shift ); } /* Wyckoff positions */ wyckoffs = (int*) malloc( sizeof(int) * primitive->size ); equiv_atoms_prim = (int*) malloc( sizeof(int) * primitive->size ); for ( i = 0; i < primitive->size; i++ ) { wyckoffs[i] = -1; equiv_atoms_prim[i] = -1; } ref_get_Wyckoff_positions( wyckoffs, equiv_atoms_prim, primitive, &spacegroup, symprec ); dataset->n_atoms = cell->size; dataset->wyckoffs = (int*) malloc( sizeof(int) * cell->size ); for ( i = 0; i < cell->size; i++ ) { dataset->wyckoffs[i] = wyckoffs[ mapping_table[i] ]; } free( wyckoffs ); wyckoffs = NULL; dataset->equivalent_atoms = (int*) malloc( sizeof(int) * cell->size ); equiv_atoms = (int*) malloc( sizeof(int) * primitive->size ); for ( i = 0; i < primitive->size; i++ ) { for ( j = 0; j < cell->size; j++ ) { if ( mapping_table[j] == equiv_atoms_prim[i] ) { equiv_atoms[i] = j; break; } } } for ( i = 0; i < cell->size; i++ ) { dataset->equivalent_atoms[i] = equiv_atoms[ mapping_table[i] ]; } free( equiv_atoms ); equiv_atoms = NULL; free( equiv_atoms_prim ); equiv_atoms_prim = NULL; free( mapping_table ); mapping_table = NULL; /* Symmetry operations */ symmetry = ref_get_refined_symmetry_operations( cell, primitive->lattice, &spacegroup, symprec ); cel_free_cell( cell ); cel_free_cell( primitive ); dataset->rotations = (int (*)[3][3]) malloc(sizeof(int[3][3]) * symmetry->size ); dataset->translations = (double (*)[3]) malloc(sizeof(double[3]) * symmetry->size ); dataset->n_operations = symmetry->size; for ( i = 0; i < symmetry->size; i++ ) { mat_copy_matrix_i3( dataset->rotations[i], symmetry->rot[i] ); mat_copy_vector_d3( dataset->translations[i], symmetry->trans[i] ); } sym_free_symmetry( symmetry ); return dataset; }
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; }
/* Return NULL if failed */ 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_exact_positions\n"); indep_atoms = NULL; positions = NULL; if ((indep_atoms = (int*) malloc(sizeof(int) * bravais->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return NULL; } if ((positions = mat_alloc_VecDBL(bravais->size)) == NULL) { free(indep_atoms); indep_atoms = NULL; return NULL; } 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++) { positions->vec[i][l] = mat_Dmod1(pos[l]); } 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; for (i = 0; i < bravais->size; i++) { if (wyckoffs[i] == -1) { mat_free_VecDBL(positions); positions = NULL; break; } } return positions; }
/* Return -1 if failed */ 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; int indices_wyc[2]; int rot[3][3]; double trans[3], orbit[3]; VecDBL *pos_rot; debug_print("get_Wyckoff_notation\n"); wyckoff_letter = -1; pos_rot = NULL; if ((pos_rot = mat_alloc_VecDBL(conv_sym->size)) == NULL) { return -1; } 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; }
/* Return if failed */ VecDBL * ssm_get_exact_positions(int *wyckoffs, int *equiv_atoms, const Cell * conv_prim, const Symmetry * conv_sym, const int hall_number, const double symprec) { int attempt, num_atoms; double tolerance; VecDBL *positions; positions = NULL; if ((positions = mat_alloc_VecDBL(conv_prim->size)) == NULL) { return NULL; } tolerance = symprec; for (attempt = 0; attempt < NUM_ATTEMPT; attempt++) { num_atoms = get_exact_positions(positions, equiv_atoms, conv_prim, conv_sym, tolerance); if (num_atoms == conv_prim->size) { goto succeeded; } if (num_atoms > conv_prim->size || num_atoms == 0) { tolerance *= INCREASE_RATE; warning_print("spglib: Some site-symmetry is found broken. "); warning_print("(%d != %d)\n", num_atoms, conv_prim->size); warning_print(" Increase tolerance to %f", tolerance); warning_print(" (%d)", attempt); warning_print(" (line %d, %s).\n", __LINE__, __FILE__); } if (num_atoms < conv_prim->size && num_atoms) { tolerance *= REDUCE_RATE; warning_print("spglib: Some site-symmetry is found broken. "); warning_print("(%d != %d)\n", num_atoms, conv_prim->size); warning_print(" Reduce tolerance to %f", tolerance); warning_print(" (%d)", attempt); warning_print(" (line %d, %s).\n", __LINE__, __FILE__); } } mat_free_VecDBL(positions); positions = NULL; return NULL; succeeded: if (! set_Wyckoffs_labels(wyckoffs, positions, equiv_atoms, conv_prim, conv_sym, hall_number, symprec)) { mat_free_VecDBL(positions); positions = NULL; } return positions; }
/* 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 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; }
/* Return 0 if failed */ static int get_primitive_lattice_vectors_iterative(double prim_lattice[3][3], SPGCONST Cell * cell, const VecDBL * pure_trans, const double symprec) { int i, multi, attempt; double tolerance; VecDBL * vectors, * pure_trans_reduced, *tmp_vec; vectors = NULL; pure_trans_reduced = NULL; tmp_vec = NULL; tolerance = symprec; if ((pure_trans_reduced = mat_alloc_VecDBL(pure_trans->size)) == NULL) { goto fail; } for (i = 0; i < pure_trans->size; i++) { mat_copy_vector_d3(pure_trans_reduced->vec[i], pure_trans->vec[i]); } for (attempt = 0; attempt < 100; attempt++) { multi = pure_trans_reduced->size; if ((vectors = get_translation_candidates(pure_trans_reduced)) == NULL) { mat_free_VecDBL(pure_trans_reduced); goto fail; } /* Lattice of primitive cell is found among pure translation vectors */ if (get_primitive_lattice_vectors(prim_lattice, vectors, cell, tolerance)) { mat_free_VecDBL(vectors); mat_free_VecDBL(pure_trans_reduced); goto found; } else { if ((tmp_vec = mat_alloc_VecDBL(multi)) == NULL) { mat_free_VecDBL(vectors); mat_free_VecDBL(pure_trans_reduced); goto fail; } for (i = 0; i < multi; i++) { mat_copy_vector_d3(tmp_vec->vec[i], pure_trans_reduced->vec[i]); } mat_free_VecDBL(pure_trans_reduced); pure_trans_reduced = sym_reduce_pure_translation(cell, tmp_vec, tolerance); mat_free_VecDBL(tmp_vec); mat_free_VecDBL(vectors); if (pure_trans_reduced == NULL) { goto fail; } warning_print("Tolerance is reduced to %f (%d), size = %d\n", tolerance, attempt, pure_trans_reduced->size); tolerance *= REDUCE_RATE; } } mat_free_VecDBL(pure_trans_reduced); fail: return 0; found: return multi; }
/* Return NULL if failed */ static Cell * get_bravais_exact_positions_and_lattice(int * wyckoffs, int * equiv_atoms, SPGCONST Spacegroup *spacegroup, SPGCONST Cell * primitive, const double symprec) { int i; int *wyckoffs_prim, *equiv_atoms_prim; Symmetry *conv_sym; Cell *bravais, *conv_prim; VecDBL *exact_positions; debug_print("get_bravais_exact_positions_and_lattice\n"); wyckoffs_prim = NULL; equiv_atoms_prim = NULL; conv_prim = NULL; bravais = NULL; conv_sym = NULL; exact_positions = NULL; /* Symmetrize atomic positions of conventional unit cell */ if ((wyckoffs_prim = (int*)malloc(sizeof(int) * primitive->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return NULL; } if ((equiv_atoms_prim = (int*)malloc(sizeof(int) * primitive->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); free(wyckoffs_prim); wyckoffs_prim = NULL; return NULL; } for (i = 0; i < primitive->size; i++) { wyckoffs_prim[i] = -1; equiv_atoms_prim[i] = -1; } /* Positions of primitive atoms are represented wrt Bravais lattice */ if ((conv_prim = get_conventional_primitive(spacegroup, primitive)) == NULL) { free(wyckoffs_prim); wyckoffs_prim = NULL; free(equiv_atoms_prim); equiv_atoms_prim = NULL; return NULL; } /* Symmetries in database (wrt Bravais lattice) */ if ((conv_sym = spgdb_get_spacegroup_operations(spacegroup->hall_number)) == NULL) { goto err; } /* Lattice vectors are set. */ get_conventional_lattice(conv_prim->lattice, spacegroup); if ((exact_positions = ssm_get_exact_positions(wyckoffs_prim, equiv_atoms_prim, conv_prim, conv_sym, spacegroup->hall_number, symprec)) == NULL) { sym_free_symmetry(conv_sym); conv_sym = NULL; goto err; } for (i = 0; i < conv_prim->size; i++) { mat_copy_vector_d3(conv_prim->position[i], exact_positions->vec[i]); } bravais = expand_positions(wyckoffs, equiv_atoms, conv_prim, conv_sym, wyckoffs_prim, equiv_atoms_prim); mat_free_VecDBL(exact_positions); exact_positions = NULL; sym_free_symmetry(conv_sym); conv_sym = NULL; err: free(wyckoffs_prim); wyckoffs_prim = NULL; free(equiv_atoms_prim); equiv_atoms_prim = NULL; cel_free_cell(conv_prim); conv_prim = NULL; return bravais; }