static Symmetry * get_refined_symmetry_operations(SPGCONST Cell * cell, SPGCONST Cell * primitive, SPGCONST Spacegroup * spacegroup, const double symprec) { int t_mat_int[3][3]; int frame[3]; double inv_mat[3][3], t_mat[3][3]; Symmetry *conv_sym, *prim_sym, *symmetry; /* Primitive symmetry from database */ conv_sym = get_db_symmetry(spacegroup->hall_number); set_translation_with_origin_shift(conv_sym, spacegroup->origin_shift); mat_inverse_matrix_d3(inv_mat, primitive->lattice, symprec); mat_multiply_matrix_d3(t_mat, inv_mat, spacegroup->bravais_lattice); prim_sym = get_primitive_db_symmetry(t_mat, conv_sym, symprec); /* Input cell symmetry from primitive symmetry */ mat_inverse_matrix_d3(inv_mat, primitive->lattice, symprec); mat_multiply_matrix_d3(t_mat, inv_mat, cell->lattice); mat_cast_matrix_3d_to_3i(t_mat_int, t_mat); get_surrounding_frame(frame, t_mat_int); symmetry = reduce_symmetry_in_frame(frame, prim_sym, t_mat_int, cell->lattice, cell->size / primitive->size, symprec); /* sym_free_symmetry(f_sym); */ sym_free_symmetry(prim_sym); sym_free_symmetry(conv_sym); return symmetry; }
VecDBL * sym_reduce_pure_translation(SPGCONST Cell * cell, const VecDBL * pure_trans, const double symprec) { int i, multi; Symmetry *symmetry, *symmetry_reduced; VecDBL * pure_trans_reduced; multi = pure_trans->size; symmetry = sym_alloc_symmetry(multi); for (i = 0; i < multi; i++) { mat_copy_matrix_i3(symmetry->rot[i], identity); mat_copy_vector_d3(symmetry->trans[i], pure_trans->vec[i]); } symmetry_reduced = reduce_operation(cell, symmetry, symprec); sym_free_symmetry(symmetry); multi = symmetry_reduced->size; pure_trans_reduced = mat_alloc_VecDBL(multi); for (i = 0; i < multi; i++) { mat_copy_vector_d3(pure_trans_reduced->vec[i], symmetry_reduced->trans[i]); } sym_free_symmetry(symmetry_reduced); return pure_trans_reduced; }
static int get_hall_number( double origin_shift[3], double conv_lattice[3][3], Centering * centering, SPGCONST Cell * primitive, SPGCONST Symmetry * symmetry, const double symprec ) { int pg_num, attempt, hall_number=0; double tolerance; Symmetry * sym_reduced; tolerance = symprec; pg_num = ptg_get_pointgroup_number( symmetry ); if ( pg_num > -1 ) { hall_number = get_hall_number_local( origin_shift, conv_lattice, centering, primitive, symmetry, symprec ); if ( hall_number > 0 ) { goto ret; } } /* Reduce tolerance and search hall symbol again when hall symbol */ /* could not be found by the given tolerance. */ /* The situation this happens is that symmetry operations found */ /* don't match any of hall symbol database due to tricky */ /* displacements of atoms from the exact points. */ for ( attempt = 0; attempt < 100; attempt++ ) { tolerance *= REDUCE_RATE; 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, centering, primitive, sym_reduced, symprec ); if ( hall_number > 0 ) { sym_free_symmetry( sym_reduced ); warning_print("spglib: Tolerance to find Hall symbol was changed to %f\n", tolerance); goto ret; } } sym_free_symmetry( sym_reduced ); } warning_print("spglib: Iterative attempt to find Hall symbol was failed."); ret: return hall_number; }
static int get_hall_number_local( double origin_shift[3], double conv_lattice[3][3], Centering * centering, SPGCONST Cell * primitive, SPGCONST Symmetry * symmetry, const double symprec ) { int hall_number; double trans_mat[3][3]; Symmetry * conv_symmetry; *centering = get_transformation_matrix( trans_mat, symmetry ); mat_multiply_matrix_d3( conv_lattice, primitive->lattice, trans_mat ); conv_symmetry = get_conventional_symmetry( trans_mat, *centering, symmetry ); hall_number = hal_get_hall_symbol( origin_shift, *centering, conv_lattice, conv_symmetry, symprec ); sym_free_symmetry( conv_symmetry ); return hall_number; }
int spg_get_ir_kpoints( int map[], SPGCONST double kpoints[][3], const int num_kpoint, SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const int num_atom, const int is_time_reversal, const double symprec ) { Symmetry *symmetry; Cell *cell; int num_ir_kpoint; cell = cel_alloc_cell( num_atom ); cel_set_cell( cell, lattice, position, types ); symmetry = sym_get_operation( cell, symprec ); num_ir_kpoint = kpt_get_irreducible_kpoints( map, kpoints, num_kpoint, lattice, symmetry, is_time_reversal, symprec ); cel_free_cell( cell ); sym_free_symmetry( symmetry ); return num_ir_kpoint; }
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 * spn_get_collinear_operations(int equiv_atoms[], SPGCONST Symmetry *sym_nonspin, SPGCONST Cell *cell, const double spins[], const double symprec) { Symmetry *symmetry; symmetry = NULL; if ((symmetry = get_collinear_operations(sym_nonspin, cell, spins, symprec)) == NULL) { return NULL; } if ((set_equivalent_atoms(equiv_atoms, symmetry, cell, symprec)) == 0) { sym_free_symmetry(symmetry); symmetry = NULL; } return symmetry; }
int spg_get_ir_reciprocal_mesh( int grid_point[][3], int map[], const int mesh[3], const int is_shift[3], const int is_time_reversal, SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const int num_atom, const double symprec ) { Symmetry *symmetry; Cell *cell; int num_ir; cell = cel_alloc_cell( num_atom ); cel_set_cell( cell, lattice, position, types ); symmetry = sym_get_operation( cell, symprec ); num_ir = kpt_get_irreducible_reciprocal_mesh( grid_point, map, mesh, is_shift, is_time_reversal, lattice, symmetry, symprec ); cel_free_cell( cell ); sym_free_symmetry( symmetry ); return num_ir; }
/* 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; }
static Symmetry * recover_symmetry_in_original_cell(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) { Symmetry *symmetry, *t_sym; double inv_tmat[3][3], tmp_mat[3][3]; VecDBL *pure_trans, *lattice_trans; symmetry = NULL; t_sym = NULL; pure_trans = NULL; lattice_trans = NULL; mat_cast_matrix_3i_to_3d(tmp_mat, t_mat); mat_inverse_matrix_d3(inv_tmat, tmp_mat, 0); if ((lattice_trans = get_lattice_translations(frame, inv_tmat)) == NULL) { return NULL; } if ((pure_trans = remove_overlapping_lattice_points(lattice, lattice_trans, symprec)) == NULL) { mat_free_VecDBL(lattice_trans); lattice_trans = NULL; return NULL; } if ((t_sym = get_symmetry_in_original_cell(t_mat, inv_tmat, lattice, prim_sym, symprec)) == NULL) { mat_free_VecDBL(pure_trans); pure_trans = NULL; mat_free_VecDBL(lattice_trans); lattice_trans = NULL; return NULL; } if (pure_trans->size == multiplicity) { symmetry = copy_symmetry_upon_lattice_points(pure_trans, t_sym); } mat_free_VecDBL(lattice_trans); lattice_trans = NULL; mat_free_VecDBL(pure_trans); pure_trans = NULL; sym_free_symmetry(t_sym); t_sym = NULL; return symmetry; }
/* Return 0 if failed */ static int iterative_search_hall_number(double origin_shift[3], double conv_lattice[3][3], const int candidates[], const int num_candidates, SPGCONST Cell * primitive, SPGCONST Symmetry * symmetry, const double symprec) { int attempt, hall_number; double tolerance; Symmetry * sym_reduced; debug_print("iterative_search_hall_number:\n"); hall_number = 0; sym_reduced = NULL; hall_number = search_hall_number(origin_shift, conv_lattice, candidates, num_candidates, primitive->lattice, symmetry, symprec); if (hall_number > 0) { goto ret; } tolerance = symprec; for (attempt = 0; attempt < 100; attempt++) { warning_print("spglib: Attempt %d tolerance = %f failed", attempt, tolerance); warning_print("(line %d, %s).\n", __LINE__, __FILE__); tolerance *= REDUCE_RATE; sym_reduced = sym_reduce_operation(primitive, symmetry, tolerance); hall_number = search_hall_number(origin_shift, conv_lattice, candidates, num_candidates, primitive->lattice, sym_reduced, symprec); sym_free_symmetry(sym_reduced); sym_reduced = NULL; if (hall_number > 0) { break; } } ret: return hall_number; }
static void set_dataset(SpglibDataset * dataset, SPGCONST Cell * cell, SPGCONST Cell * primitive, SPGCONST Spacegroup * spacegroup, const int * mapping_table, const double tolerance) { int i; double inv_mat[3][3]; Cell *bravais; Symmetry *symmetry; /* Spacegroup type, transformation matrix, origin shift */ dataset->n_atoms = cell->size; dataset->spacegroup_number = spacegroup->number; dataset->hall_number = spacegroup->hall_number; strcpy(dataset->international_symbol, spacegroup->international_short); strcpy(dataset->hall_symbol, spacegroup->hall_symbol); strcpy(dataset->setting, spacegroup->setting); mat_inverse_matrix_d3(inv_mat, cell->lattice, tolerance); mat_multiply_matrix_d3(dataset->transformation_matrix, inv_mat, spacegroup->bravais_lattice); mat_copy_vector_d3(dataset->origin_shift, spacegroup->origin_shift); /* Symmetry operations */ symmetry = ref_get_refined_symmetry_operations(cell, primitive, spacegroup, tolerance); 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]); } /* Wyckoff positions */ dataset->wyckoffs = (int*) malloc(sizeof(int) * cell->size); dataset->equivalent_atoms = (int*) malloc(sizeof(int) * cell->size); bravais = ref_get_Wyckoff_positions(dataset->wyckoffs, dataset->equivalent_atoms, primitive, cell, spacegroup, symmetry, mapping_table, tolerance); cel_free_cell(bravais); sym_free_symmetry(symmetry); }
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_symmetry_with_collinear_spin(int rotation[][3][3], double translation[][3], const int max_size, SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const double spins[], const int num_atom, const double symprec) { int i, j, size; Symmetry *symmetry; Cell *cell; cell = cel_alloc_cell(num_atom); cel_set_cell(cell, lattice, position, types); symmetry = spn_get_collinear_operation(cell, spins, symprec); if (symmetry->size > max_size) { fprintf(stderr, "spglib: Indicated max size(=%d) is less than number ", max_size); fprintf(stderr, "spglib: of symmetry operations(=%d).\n", symmetry->size); sym_free_symmetry(symmetry); return 0; } for (i = 0; i < symmetry->size; i++) { mat_copy_matrix_i3(rotation[i], symmetry->rot[i]); for (j = 0; j < 3; j++) { translation[i][j] = symmetry->trans[i][j]; } } size = symmetry->size; cel_free_cell(cell); sym_free_symmetry(symmetry); return size; }
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 Symmetry * recover_operations_original(SPGCONST Symmetry *symmetry, const VecDBL * pure_trans, SPGCONST Cell *cell, SPGCONST Cell *primitive) { int i, j, k, multi; double inv_prim_lat[3][3], drot[3][3], trans_mat[3][3], trans_mat_inv[3][3]; Symmetry *symmetry_orig, *sym_tmp; debug_print("recover_operations_original:\n"); multi = pure_trans->size; sym_tmp = sym_alloc_symmetry(symmetry->size); symmetry_orig = sym_alloc_symmetry(symmetry->size * multi); mat_inverse_matrix_d3(inv_prim_lat, primitive->lattice, 0); mat_multiply_matrix_d3(trans_mat, inv_prim_lat, cell->lattice); mat_inverse_matrix_d3(trans_mat_inv, trans_mat, 0); for(i = 0; i < symmetry->size; i++) { mat_copy_matrix_i3(sym_tmp->rot[i], symmetry->rot[i]); mat_copy_vector_d3(sym_tmp->trans[i], symmetry->trans[i]); } for(i = 0; i < symmetry->size; i++) { mat_cast_matrix_3i_to_3d(drot, sym_tmp->rot[i]); mat_get_similar_matrix_d3(drot, drot, trans_mat, 0); mat_cast_matrix_3d_to_3i(sym_tmp->rot[i], drot); mat_multiply_matrix_vector_d3(sym_tmp->trans[i], trans_mat_inv, sym_tmp->trans[i]); } for(i = 0; i < symmetry->size; i++) { for(j = 0; j < multi; j++) { mat_copy_matrix_i3(symmetry_orig->rot[i * multi + j], sym_tmp->rot[i]); for (k = 0; k < 3; k++) { symmetry_orig->trans[i * multi + j][k] = sym_tmp->trans[i][k] + pure_trans->vec[j][k]; } } } sym_free_symmetry(sym_tmp); return symmetry_orig; }
/* Return 0 if failed */ static int get_symmetry_numerical(int rotation[][3][3], double translation[][3], const int max_size, SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const int num_atom, const double symprec) { int i, size; Cell *cell; Symmetry *symmetry; size = 0; cell = NULL; symmetry = NULL; if ((cell = cel_alloc_cell(num_atom)) == NULL) { return 0; } cel_set_cell(cell, lattice, position, types); if ((symmetry = sym_get_operation(cell, symprec)) == NULL) { cel_free_cell(cell); return 0; } if (symmetry->size > max_size) { fprintf(stderr, "spglib: Indicated max size(=%d) is less than number ", max_size); fprintf(stderr, "spglib: of symmetry operations(=%d).\n", symmetry->size); goto ret; } for (i = 0; i < symmetry->size; i++) { mat_copy_matrix_i3(rotation[i], symmetry->rot[i]); mat_copy_vector_d3(translation[i], symmetry->trans[i]); } size = symmetry->size; ret: sym_free_symmetry(symmetry); cel_free_cell(cell); return size; }
static Cell * refine_cell( SPGCONST Cell * cell, const double symprec ) { int *mapping_table, *wyckoffs, *equiv_atoms; Cell *primitive, *bravais, *conv_prim; Symmetry *conv_sym; VecDBL *pure_trans; Spacegroup spacegroup; 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 ); free( mapping_table ); mapping_table = NULL; if ( primitive->size == -1 ) { cel_free_cell( primitive ); bravais = cel_alloc_cell( -1 ); goto ret; } spacegroup = spa_get_spacegroup_with_primitive( primitive, symprec ); 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, symprec ); 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 ); cel_free_cell( conv_prim ); sym_free_symmetry( conv_sym ); cel_free_cell( primitive ); ret: /* Return bravais->size = -1, if the bravais could not be found. */ return bravais; }
/* 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_get_multiplicity( SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const int num_atom, const double symprec ) { Symmetry *symmetry; Cell *cell; int size; cell = cel_alloc_cell( num_atom ); cel_set_cell( cell, lattice, position, types ); symmetry = sym_get_operation( cell, symprec ); size = symmetry->size; cel_free_cell( cell ); sym_free_symmetry( symmetry ); return size; }
/* Return 0 if failed */ int spg_get_symmetry_from_database(int rotations[192][3][3], double translations[192][3], const int hall_number) { int i, size; Symmetry *symmetry; symmetry = NULL; if ((symmetry = spgdb_get_spacegroup_operations(hall_number)) == NULL) { return 0; } for (i = 0; i < symmetry->size; i++) { mat_copy_matrix_i3(rotations[i], symmetry->rot[i]); mat_copy_vector_d3(translations[i], symmetry->trans[i]); } size = symmetry->size; sym_free_symmetry(symmetry); return size; }
/* 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; }
/* 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 0 if failed */ static int match_hall_symbol_db_monocli(double origin_shift[3], double lattice[3][3], const int hall_number, const int num_hall_types, const Centering centering, SPGCONST Symmetry *symmetry, const double symprec) { int i, j, k, l, is_found; double vec[3], norms[3]; Centering changed_centering; Symmetry * changed_symmetry; double changed_lattice[3][3]; changed_symmetry = NULL; for (i = 0; i < 18; i++) { if (centering == C_FACE) { changed_centering = change_of_centering_monocli[i]; } else { /* suppose PRIMITIVE */ changed_centering = centering; } mat_multiply_matrix_d3(changed_lattice, lattice, change_of_basis_monocli[i]); /* Choose |a| < |b| < |c| if there are freedom. */ if (num_hall_types == 3) { l = 0; for (j = 0; j < 3; j++) { if (j == change_of_unique_axis_monocli[i]) {continue;} for (k = 0; k < 3; k++) {vec[k] = changed_lattice[k][j];} norms[l] = mat_norm_squared_d3(vec); l++; } if (norms[0] > norms[1]) {continue;} } if ((changed_symmetry = get_conventional_symmetry(change_of_basis_monocli[i], PRIMITIVE, symmetry)) == NULL) { goto err; } is_found = hal_match_hall_symbol_db(origin_shift, changed_lattice, hall_number, changed_centering, changed_symmetry, symprec); sym_free_symmetry(changed_symmetry); changed_symmetry = NULL; if (is_found) { mat_copy_matrix_d3(lattice, changed_lattice); return 1; } } err: return 0; }
/* Return NULL if failed */ static Symmetry * get_symmetry_in_original_cell(SPGCONST int t_mat[3][3], SPGCONST double inv_tmat[3][3], SPGCONST double lattice[3][3], SPGCONST Symmetry *prim_sym, const double symprec) { int i, size_sym_orig; double tmp_rot_d[3][3], tmp_lat_d[3][3], tmp_lat_i[3][3], tmp_mat[3][3]; int tmp_rot_i[3][3]; Symmetry *t_sym, *t_red_sym; t_sym = NULL; t_red_sym = NULL; if ((t_sym = sym_alloc_symmetry(prim_sym->size)) == NULL) { return NULL; } /* transform symmetry operations of primitive cell to those of original */ 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); /* In spglib, symmetry of supercell is defined by the set of symmetry */ /* operations that are searched among supercell lattice point group */ /* operations. The supercell lattice may be made by breaking the */ /* unit cell lattice symmetry. In this case, a part of symmetry */ /* operations is discarded. */ 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++; } } /* Broken symmetry due to supercell multiplicity */ if (size_sym_orig != prim_sym->size) { if ((t_red_sym = sym_alloc_symmetry(size_sym_orig)) == NULL) { sym_free_symmetry(t_sym); t_sym = NULL; return NULL; } for (i = 0; i < size_sym_orig; i++) { mat_copy_matrix_i3(t_red_sym->rot[i], t_sym->rot[i]); mat_copy_vector_d3(t_red_sym->trans[i], t_sym->trans[i]); } sym_free_symmetry(t_sym); t_sym = NULL; t_sym = t_red_sym; t_red_sym = NULL; } return t_sym; }
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 * 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; }
/* Return 0 if failed */ static int get_symmetry_with_collinear_spin(int rotation[][3][3], double translation[][3], int equivalent_atoms[], const int max_size, SPGCONST double lattice[3][3], SPGCONST double position[][3], const int types[], const double spins[], const int num_atom, const double symprec) { int i, size; Symmetry *symmetry, *sym_nonspin; Cell *cell; SpglibDataset *dataset; size = 0; symmetry = NULL; sym_nonspin = NULL; cell = NULL; dataset = NULL; if ((cell = cel_alloc_cell(num_atom)) == NULL) { goto err; } cel_set_cell(cell, lattice, position, types); if ((dataset = get_dataset(lattice, position, types, num_atom, 0, symprec)) == NULL) { cel_free_cell(cell); goto err; } if ((sym_nonspin = sym_alloc_symmetry(dataset->n_operations)) == NULL) { spg_free_dataset(dataset); cel_free_cell(cell); goto err; } for (i = 0; i < dataset->n_operations; i++) { mat_copy_matrix_i3(sym_nonspin->rot[i], dataset->rotations[i]); mat_copy_vector_d3(sym_nonspin->trans[i], dataset->translations[i]); } spg_free_dataset(dataset); if ((symmetry = spn_get_collinear_operations(equivalent_atoms, sym_nonspin, cell, spins, symprec)) == NULL) { sym_free_symmetry(sym_nonspin); cel_free_cell(cell); goto err; } sym_free_symmetry(sym_nonspin); if (symmetry->size > max_size) { fprintf(stderr, "spglib: Indicated max size(=%d) is less than number ", max_size); fprintf(stderr, "spglib: of symmetry operations(=%d).\n", symmetry->size); sym_free_symmetry(symmetry); goto err; } for (i = 0; i < symmetry->size; i++) { mat_copy_matrix_i3(rotation[i], symmetry->rot[i]); mat_copy_vector_d3(translation[i], symmetry->trans[i]); } size = symmetry->size; cel_free_cell(cell); sym_free_symmetry(symmetry); return size; err: return 0; }
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 0 if failed */ static int set_dataset(SpglibDataset * dataset, SPGCONST Cell * cell, SPGCONST Cell * primitive, SPGCONST Spacegroup * spacegroup, const int * mapping_table, const double tolerance) { int i; double inv_mat[3][3]; Cell *bravais; Symmetry *symmetry; bravais = NULL; symmetry = NULL; /* Spacegroup type, transformation matrix, origin shift */ dataset->n_atoms = cell->size; dataset->spacegroup_number = spacegroup->number; dataset->hall_number = spacegroup->hall_number; strcpy(dataset->international_symbol, spacegroup->international_short); strcpy(dataset->hall_symbol, spacegroup->hall_symbol); strcpy(dataset->setting, spacegroup->setting); mat_inverse_matrix_d3(inv_mat, cell->lattice, tolerance); mat_multiply_matrix_d3(dataset->transformation_matrix, inv_mat, spacegroup->bravais_lattice); mat_copy_vector_d3(dataset->origin_shift, spacegroup->origin_shift); /* Symmetry operations */ if ((symmetry = ref_get_refined_symmetry_operations(cell, primitive, spacegroup, tolerance)) == NULL) { return 0; } dataset->n_operations = symmetry->size; if ((dataset->rotations = (int (*)[3][3]) malloc(sizeof(int[3][3]) * dataset->n_operations)) == NULL) { warning_print("spglib: Memory could not be allocated."); goto err; } if ((dataset->translations = (double (*)[3]) malloc(sizeof(double[3]) * dataset->n_operations)) == NULL) { warning_print("spglib: Memory could not be allocated."); goto err; } 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]); } /* Wyckoff positions */ if ((dataset->wyckoffs = (int*) malloc(sizeof(int) * dataset->n_atoms)) == NULL) { warning_print("spglib: Memory could not be allocated."); goto err; } if ((dataset->equivalent_atoms = (int*) malloc(sizeof(int) * dataset->n_atoms)) == NULL) { warning_print("spglib: Memory could not be allocated."); goto err; } if ((bravais = ref_get_Wyckoff_positions(dataset->wyckoffs, dataset->equivalent_atoms, primitive, cell, spacegroup, symmetry, mapping_table, tolerance)) == NULL) { goto err; } dataset->n_brv_atoms = bravais->size; mat_copy_matrix_d3(dataset->brv_lattice, bravais->lattice); if ((dataset->brv_positions = (double (*)[3]) malloc(sizeof(double[3]) * dataset->n_brv_atoms)) == NULL) { warning_print("spglib: Memory could not be allocated."); goto err; } if ((dataset->brv_types = (int*) malloc(sizeof(int) * dataset->n_brv_atoms)) == NULL) { warning_print("spglib: Memory could not be allocated."); goto err; } for (i = 0; i < dataset->n_brv_atoms; i++) { mat_copy_vector_d3(dataset->brv_positions[i], bravais->position[i]); dataset->brv_types[i] = bravais->types[i]; } cel_free_cell(bravais); sym_free_symmetry(symmetry); return 1; err: if (dataset->brv_positions != NULL) { free(dataset->brv_positions); dataset->brv_positions = NULL; } if (bravais != NULL) { cel_free_cell(bravais); } if (dataset->equivalent_atoms != NULL) { free(dataset->equivalent_atoms); dataset->equivalent_atoms = NULL; } if (dataset->wyckoffs != NULL) { free(dataset->wyckoffs); dataset->wyckoffs = NULL; } if (dataset->translations != NULL) { free(dataset->translations); dataset->translations = NULL; } if (dataset->rotations != NULL) { free(dataset->rotations); dataset->rotations = NULL; } if (symmetry != NULL) { sym_free_symmetry(symmetry); } return 0; }