phonopy/c/spglib/site_symmetry.c

232 lines
5.7 KiB
C
Raw Normal View History

2012-12-11 16:15:20 +08:00
/* site_symmetry.c */
/* Copyright (C) 2011 Atsushi Togo */
#include <stdio.h>
#include <stdlib.h>
#include "cell.h"
#include "mathfunc.h"
#include "symmetry.h"
#include "sitesym_database.h"
#include "debug.h"
static VecDBL * get_exact_positions(int * wyckoffs,
int * equiv_atoms,
SPGCONST Cell * bravais,
SPGCONST Symmetry * conv_sym,
const int hall_number,
const double symprec);
static void get_exact_location(double position[3],
SPGCONST Symmetry * conv_sym,
SPGCONST double bravais_lattice[3][3],
const double symprec);
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);
VecDBL * ssm_get_exact_positions(int *wyckoffs,
int *equiv_atoms,
SPGCONST Cell * bravais,
SPGCONST Symmetry * conv_sym,
const int hall_number,
const double symprec)
{
return get_exact_positions(wyckoffs,
equiv_atoms,
bravais,
conv_sym,
hall_number,
symprec);
}
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;
}
/* Site-symmetry is used to determine exact location of an atom */
/* R. W. Grosse-Kunstleve and P. D. Adams */
/* Acta Cryst. (2002). A58, 60-65 */
static void get_exact_location(double position[3],
SPGCONST Symmetry * conv_sym,
SPGCONST double bravais_lattice[3][3],
const double symprec)
{
int i, j, k, num_sum;
double sum_rot[3][3];
double pos[3], sum_trans[3];
num_sum = 0;
for (i = 0; i < 3; i++) {
sum_trans[i] = 0.0;
for (j = 0; j < 3; j++) {
sum_rot[i][j] = 0;
}
}
for (i = 0; i < conv_sym->size; i++) {
mat_multiply_matrix_vector_id3(pos,
conv_sym->rot[i],
position);
for (j = 0; j < 3; j++) {
pos[j] += conv_sym->trans[i][j];
}
if (cel_is_overlap(pos,
position,
bravais_lattice,
symprec)) {
for (j = 0; j < 3; j++) {
sum_trans[j] += conv_sym->trans[i][j] -
mat_Nint(pos[j] - position[j]);
for (k = 0; k < 3; k++) {
sum_rot[j][k] += conv_sym->rot[i][j][k];
}
}
num_sum++;
}
}
for (i = 0; i < 3; i++) {
sum_trans[i] /= num_sum;
for (j = 0; j < 3; j++) {
sum_rot[i][j] /= num_sum;
}
}
/* (sum_rot|sum_trans) is the special-position operator. */
/* Elements of sum_rot can be fractional values. */
mat_multiply_matrix_vector_d3(position,
sum_rot,
position);
for (i = 0; i < 3; i++) {
position[i] += sum_trans[i];
}
}
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=-1;
int indices_wyc[2];
int rot[3][3];
double trans[3], orbit[3];
VecDBL *pos_rot;
pos_rot = mat_alloc_VecDBL(conv_sym->size);
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;
}