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; tolerance = symprec; pure_trans_reduced = mat_alloc_VecDBL( pure_trans->size ); 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; vectors = get_translation_candidates( pure_trans_reduced ); /* 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 { tmp_vec = mat_alloc_VecDBL( multi ); 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 ); debug_print("Tolerance is reduced to %f (%d), size = %d\n", tolerance, attempt, pure_trans_reduced->size); mat_free_VecDBL( tmp_vec ); mat_free_VecDBL( vectors ); tolerance *= REDUCE_RATE; } } /* Not found */ return 0; found: #ifdef SPGWARNING if ( attempt > 0 ) { printf("spglib: Tolerance to find primitive lattice vectors was changed to %f ", tolerance); } #endif return multi; }
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 VecDBL * reduce_lattice_points(SPGCONST double lattice[3][3], const VecDBL *lattice_trans, const double symprec) { int i, j, is_found, num_pure_trans; VecDBL *pure_trans, *t; num_pure_trans = 0; t = mat_alloc_VecDBL(lattice_trans->size); for (i = 0; i < lattice_trans->size; i++) { is_found = 0; for (j = 0; j < num_pure_trans; 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_pure_trans], lattice_trans->vec[i]); num_pure_trans++; } } pure_trans = mat_alloc_VecDBL(num_pure_trans); for (i = 0; i < num_pure_trans; i++) { mat_copy_vector_d3(pure_trans->vec[i], t->vec[i]); } mat_free_VecDBL(t); return pure_trans; }
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 void get_Delaunay_shortest_vectors( double basis[4][3], const double symprec ) { int i, j; double tmpmat[3][3], b[7][3], tmpvec[3]; /* Search in the set {b1, b2, b3, b4, b1+b2, b2+b3, b3+b1} */ for ( i = 0; i < 4; i++ ) { for ( j = 0; j < 3; j++ ) { b[i][j] = basis[i][j]; } } for ( i = 0; i < 3; i++ ) { b[4][i] = basis[0][i] + basis[1][i]; } for ( i = 0; i < 3; i++ ) { b[5][i] = basis[1][i] + basis[2][i]; } for ( i = 0; i < 3; i++ ) { b[6][i] = basis[2][i] + basis[0][i]; } /* Bubble sort */ for ( i = 0; i < 6; i++ ) { for ( j = 0; j < 6; j++ ) { if ( mat_norm_squared_d3( b[j] ) > mat_norm_squared_d3( b[j+1] ) ) { mat_copy_vector_d3( tmpvec, b[j] ); mat_copy_vector_d3( b[j], b[j+1] ); mat_copy_vector_d3( b[j+1], tmpvec ); } } } for ( i = 2; i < 7; i++ ) { for ( j = 0; j < 3; j++ ) { tmpmat[j][0] = b[0][j]; tmpmat[j][1] = b[1][j]; tmpmat[j][2] = b[i][j]; } if ( mat_Dabs( mat_get_determinant_d3( tmpmat ) ) > symprec ) { for ( j = 0; j < 3; j++ ) { basis[0][j] = b[0][j]; basis[1][j] = b[1][j]; basis[2][j] = b[i][j]; } break; } } }
/* Return NULL if failed */ static Symmetry * copy_symmetry_upon_lattice_points(const VecDBL *pure_trans, SPGCONST Symmetry *t_sym) { int i, j, k, size_sym_orig; Symmetry *symmetry; symmetry = NULL; size_sym_orig = t_sym->size; if ((symmetry = sym_alloc_symmetry(pure_trans->size * size_sym_orig)) == NULL) { return NULL; } 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]); } } } return symmetry; }
static int find_primitive(double lattice[3][3], double position[][3], int types[], const int num_atom, const double symprec) { int i, num_prim_atom=0; Cell *cell, *primitive; cell = cel_alloc_cell(num_atom); cel_set_cell(cell, lattice, position, types); /* find primitive cell */ primitive = prm_get_primitive(cell, symprec); if (primitive->size == cell->size) { /* Already primitive */ num_prim_atom = 0; } else { /* Primitive cell was found. */ 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]; mat_copy_vector_d3(position[i], primitive->position[i]); } } } cel_free_cell(primitive); cel_free_cell(cell); return num_prim_atom; }
int spg_refine_cell( double lattice[3][3], double position[][3], int types[], const int num_atom, const double symprec ) { int i, num_atom_bravais; Cell *cell, *bravais; cell = cel_alloc_cell( num_atom ); cel_set_cell( cell, lattice, position, types ); bravais = ref_refine_cell( cell, symprec ); cel_free_cell( cell ); if ( bravais->size > 0 ) { mat_copy_matrix_d3( lattice, bravais->lattice ); num_atom_bravais = bravais->size; for ( i = 0; i < bravais->size; i++ ) { types[i] = bravais->types[i]; mat_copy_vector_d3( position[i], bravais->position[i] ); } } else { num_atom_bravais = 0; } cel_free_cell( bravais ); return num_atom_bravais; }
static VecDBL * get_translation_candidates( const VecDBL * pure_trans ) { int i, j, multi; VecDBL * vectors; multi = pure_trans->size; vectors = mat_alloc_VecDBL( multi+2 ); /* store pure translations in original cell */ /* as trial primitive lattice vectors */ for (i = 0; i < multi - 1; i++) { mat_copy_vector_d3( vectors->vec[i], pure_trans->vec[i + 1]); } /* store lattice translations of original cell */ /* as trial primitive lattice vectors */ for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { if (i == j) { vectors->vec[i+multi-1][j] = 1; } else { vectors->vec[i+multi-1][j] = 0; } } } #ifdef DEBUG for (i = 0; i < multi + 2; i++) { debug_print("%d: %f %f %f\n", i + 1, vectors->vec[i][0], vectors->vec[i][1], vectors->vec[i][2]); } #endif return vectors; }
/* Return spacegroup.number = 0 if failed */ static Spacegroup get_spacegroup(const int hall_number, const double origin_shift[3], SPGCONST double conv_lattice[3][3]) { Spacegroup spacegroup; SpacegroupType spacegroup_type; spacegroup.number = 0; 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.pointgroup_number = spacegroup_type.pointgroup_number; 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); strcpy(spacegroup.setting, spacegroup_type.setting); } return spacegroup; }
static int refine_cell(double lattice[3][3], double position[][3], int types[], const int num_atom, const double symprec) { int i, n_brv_atoms; SpglibDataset *dataset; n_brv_atoms = 0; dataset = NULL; if ((dataset = get_dataset(lattice, position, types, num_atom, 0, symprec)) == NULL) { return 0; } n_brv_atoms = dataset->n_brv_atoms; mat_copy_matrix_d3(lattice, dataset->brv_lattice); for (i = 0; i < dataset->n_brv_atoms; i++) { types[i] = dataset->brv_types[i]; mat_copy_vector_d3(position[i], dataset->brv_positions[i]); } spg_free_dataset(dataset); return n_brv_atoms; }
static Cell * expand_positions(SPGCONST Cell * conv_prim, SPGCONST Symmetry * conv_sym) { int i, j, k, num_pure_trans; int num_atom; Cell * bravais; num_pure_trans = get_number_of_pure_translation(conv_sym); bravais = cel_alloc_cell(conv_prim->size * num_pure_trans); num_atom = 0; for (i = 0; i < conv_sym->size; i++) { /* Referred atoms in Bravais lattice */ if (mat_check_identity_matrix_i3(identity, conv_sym->rot[i])) { for (j = 0; j < conv_prim->size; j++) { bravais->types[num_atom] = conv_prim->types[j]; mat_copy_vector_d3(bravais->position[ num_atom ], conv_prim->position[j]); for (k = 0; k < 3; k++) { bravais->position[num_atom][k] += conv_sym->trans[i][k]; bravais->position[num_atom][k] = mat_Dmod1(bravais->position[num_atom][k]); } num_atom++; } } } mat_copy_matrix_d3(bravais->lattice, conv_prim->lattice); return bravais; }
static VecDBL * get_translation_candidates(const VecDBL * pure_trans) { int i, j, multi; VecDBL * vectors; vectors = NULL; multi = pure_trans->size; if ((vectors = mat_alloc_VecDBL(multi + 2)) == NULL) { return NULL; } /* store pure translations in original cell */ /* as trial primitive lattice vectors */ for (i = 0; i < multi - 1; i++) { mat_copy_vector_d3(vectors->vec[i], pure_trans->vec[i + 1]); } /* store lattice translations of original cell */ /* as trial primitive lattice vectors */ for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { if (i == j) { vectors->vec[i+multi-1][j] = 1; } else { vectors->vec[i+multi-1][j] = 0; } } } return vectors; }
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; }
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; }
/* This function is heaviest in this code. */ static VecDBL * get_translation( SPGCONST int rot[3][3], SPGCONST Cell *cell, const double symprec, const int is_identity ) { int i, j, min_atom_index, num_trans = 0; int *is_found; double origin[3]; VecDBL *tmp_trans, *trans; tmp_trans = mat_alloc_VecDBL( cell->size ); is_found = (int*) malloc( sizeof(int)*cell->size); for ( i = 0; i < cell->size; i++ ) { is_found[i] = 0; } /* Look for the atom index with least number of atoms within same type */ min_atom_index = get_index_with_least_atoms( cell ); /* Set min_atom_index as the origin to measure the distance between atoms. */ mat_multiply_matrix_vector_id3(origin, rot, cell->position[min_atom_index]); #pragma omp parallel for private( j ) for (i = 0; i < cell->size; i++) { /* test translation */ if (cell->types[i] != cell->types[min_atom_index]) { continue; } for (j = 0; j < 3; j++) { tmp_trans->vec[i][j] = cell->position[i][j] - origin[j]; } if ( is_overlap_all_atoms( tmp_trans->vec[i], rot, cell, symprec, is_identity ) ) { is_found[i] = 1; } } for ( i = 0; i < cell->size; i++ ) { num_trans += is_found[i]; } trans = mat_alloc_VecDBL( num_trans ); num_trans = 0; for ( i = 0; i < cell->size; i++ ) { if ( is_found[i] ) { mat_copy_vector_d3( trans->vec[num_trans], tmp_trans->vec[i] ); num_trans++; } } mat_free_VecDBL( tmp_trans ); free( is_found ); is_found = NULL; return trans; }
/* Return 0 if failed */ static int get_exact_positions(VecDBL *positions, int * equiv_atoms, const Cell * conv_prim, const Symmetry * conv_sym, const double symprec) { int i, num_indep_atoms, sum_num_atoms_in_orbits, num_atoms_in_orbits; int *indep_atoms; debug_print("get_exact_positions\n"); indep_atoms = NULL; if ((indep_atoms = (int*) malloc(sizeof(int) * conv_prim->size)) == NULL) { warning_print("spglib: Memory could not be allocated "); return 0; } num_indep_atoms = 0; sum_num_atoms_in_orbits = 0; for (i = 0; i < conv_prim->size; i++) { /* Check if atom_i overlap to an atom already set at the exact position. */ if (! set_equivalent_atom(positions, equiv_atoms, i, num_indep_atoms, indep_atoms, conv_prim, conv_sym, symprec)) { /* No equivalent atom was found. */ indep_atoms[num_indep_atoms] = i; num_indep_atoms++; mat_copy_vector_d3(positions->vec[i], conv_prim->position[i]); num_atoms_in_orbits = set_exact_location(positions->vec[i], conv_sym, conv_prim->lattice, symprec); if (num_atoms_in_orbits) { sum_num_atoms_in_orbits += num_atoms_in_orbits; equiv_atoms[i] = i; } else { sum_num_atoms_in_orbits = 0; break; } } } free(indep_atoms); indep_atoms = NULL; return sum_num_atoms_in_orbits; }
static void set_cell(double lattice[3][3], double position[][3], int types[], Cell * cell) { int i; mat_copy_matrix_d3(lattice, cell->lattice); for (i = 0; i < cell->size; i++) { types[i] = cell->types[i]; mat_copy_vector_d3(position[i], cell->position[i]); } }
int spg_get_symmetry_from_database(int rotations[192][3][3], double translations[192][3], const int hall_number) { int i; Symmetry *symmetry; symmetry = spgdb_get_spacegroup_operations(hall_number); 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]); } return symmetry->size; }
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; }
/* 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; }
/* Return 0 if failed */ static int get_symmetry_from_dataset(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, num_sym; SpglibDataset *dataset; num_sym = 0; dataset = NULL; if ((dataset = get_dataset(lattice, position, types, num_atom, 0, symprec)) == NULL) { return 0; } if (dataset->n_operations > max_size) { fprintf(stderr, "spglib: Indicated max size(=%d) is less than number ", max_size); fprintf(stderr, "spglib: of symmetry operations(=%d).\n", dataset->n_operations); goto ret; } num_sym = dataset->n_operations; for (i = 0; i < num_sym; i++) { mat_copy_matrix_i3(rotation[i], dataset->rotations[i]); mat_copy_vector_d3(translation[i], dataset->translations[i]); } ret: spg_free_dataset(dataset); return num_sym; }
static Symmetry * get_db_symmetry(const int hall_number) { int i; int operation_index[2]; int rot[3][3]; double trans[3]; Symmetry *symmetry; spgdb_get_operation_index(operation_index, hall_number); symmetry = sym_alloc_symmetry(operation_index[0]); for (i = 0; i < operation_index[0]; i++) { /* rotation matrix matching and set difference of translations */ spgdb_get_operation(rot, trans, operation_index[1] + i); mat_copy_matrix_i3(symmetry->rot[i], rot); mat_copy_vector_d3(symmetry->trans[i], trans); } return symmetry; }
/* Return 0 if failed */ static int find_primitive(double lattice[3][3], double position[][3], int types[], const int num_atom, const double symprec) { int i, num_prim_atom; Cell *cell; Primitive *primitive; cell = NULL; primitive = NULL; num_prim_atom = 0; if ((cell = cel_alloc_cell(num_atom)) == NULL) { return 0; } cel_set_cell(cell, lattice, position, types); /* find primitive cell */ if ((primitive = prm_get_primitive(cell, symprec)) == NULL) { cel_free_cell(cell); return 0; } num_prim_atom = primitive->cell->size; if (num_prim_atom < num_atom && num_prim_atom > 0 ) { mat_copy_matrix_d3(lattice, primitive->cell->lattice); for (i = 0; i < primitive->cell->size; i++) { types[i] = primitive->cell->types[i]; mat_copy_vector_d3(position[i], primitive->cell->position[i]); } } prm_free_primitive(primitive); cel_free_cell(cell); return num_prim_atom; }
/* 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; }
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; }
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_symmetrized_positions\n"); indep_atoms = (int*) malloc(sizeof(int) * bravais->size); positions = mat_alloc_VecDBL(bravais->size); 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++) { pos[l] -= mat_Nint(pos[l]); } mat_copy_vector_d3(positions->vec[i], pos); 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; 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 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; }