phonopy/c/spglib/pointgroup.c

1312 lines
28 KiB
C

/* Copyright (C) 2008 Atsushi Togo */
/* All rights reserved. */
/* This file is part of spglib. */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions */
/* are met: */
/* * Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* * Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the */
/* distribution. */
/* * Neither the name of the phonopy project nor the names of its */
/* contributors may be used to endorse or promote products derived */
/* from this software without specific prior written permission. */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE */
/* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */
/* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER */
/* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT */
/* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
/* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
/* POSSIBILITY OF SUCH DAMAGE. */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "pointgroup.h"
#include "symmetry.h"
#include "mathfunc.h"
#include "debug.h"
#define NUM_ROT_AXES 73
#define ZERO_PREC 1e-10
typedef struct {
int table[10];
char symbol[6];
char schoenflies[4];
Holohedry holohedry;
Laue laue;
} PointgroupType;
static PointgroupType pointgroup_data[33] = {
{ /* 0 */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
" ",
" ",
HOLOHEDRY_NONE,
LAUE_NONE,
},
{ /* 1 */
{0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
"1 ",
"C1 ",
TRICLI,
LAUE1,
},
{ /* 2 */
{0, 0, 0, 0, 1, 1, 0, 0, 0, 0},
"-1 ",
"Ci ",
TRICLI,
LAUE1,
},
{ /* 3 */
{0, 0, 0, 0, 0, 1, 1, 0, 0, 0},
"2 ",
"C2 ",
MONOCLI,
LAUE2M,
},
{ /* 4 */
{0, 0, 0, 1, 0, 1, 0, 0, 0, 0},
"m ",
"Cs ",
MONOCLI,
LAUE2M,
},
{ /* 5 */
{0, 0, 0, 1, 1, 1, 1, 0, 0, 0},
"2/m ",
"C2h",
MONOCLI,
LAUE2M,
},
{ /* 6 */
{0, 0, 0, 0, 0, 1, 3, 0, 0, 0},
"222 ",
"D2 ",
ORTHO,
LAUEMMM,
},
{ /* 7 */
{0, 0, 0, 2, 0, 1, 1, 0, 0, 0},
"mm2 ",
"C2v",
ORTHO,
LAUEMMM,
},
{ /* 8 */
{0, 0, 0, 3, 1, 1, 3, 0, 0, 0},
"mmm ",
"D2h",
ORTHO,
LAUEMMM,
},
{ /* 9 */
{0, 0, 0, 0, 0, 1, 1, 0, 2, 0},
"4 ",
"C4 ",
TETRA,
LAUE4M,
},
{ /* 10 */
{0, 2, 0, 0, 0, 1, 1, 0, 0, 0},
"-4 ",
"S4 ",
TETRA,
LAUE4M,
},
{ /* 11 */
{0, 2, 0, 1, 1, 1, 1, 0, 2, 0},
"4/m ",
"C4h",
TETRA,
LAUE4M,
},
{ /* 12 */
{0, 0, 0, 0, 0, 1, 5, 0, 2, 0},
"422 ",
"D4 ",
TETRA,
LAUE4MMM,
},
{ /* 13 */
{0, 0, 0, 4, 0, 1, 1, 0, 2, 0},
"4mm ",
"C4v",
TETRA,
LAUE4MMM,
},
{ /* 14 */
{0, 2, 0, 2, 0, 1, 3, 0, 0, 0},
"-42m ",
"D2d",
TETRA,
LAUE4MMM,
},
{ /* 15 */
{0, 2, 0, 5, 1, 1, 5, 0, 2, 0},
"4/mmm",
"D4h",
TETRA,
LAUE4MMM,
},
{ /* 16 */
{0, 0, 0, 0, 0, 1, 0, 2, 0, 0},
"3 ",
"C3 ",
TRIGO,
LAUE3,
},
{ /* 17 */
{0, 0, 2, 0, 1, 1, 0, 2, 0, 0},
"-3 ",
"C3i",
TRIGO,
LAUE3,
},
{ /* 18 */
{0, 0, 0, 0, 0, 1, 3, 2, 0, 0},
"32 ",
"D3 ",
TRIGO,
LAUE3M,
},
{ /* 19 */
{0, 0, 0, 3, 0, 1, 0, 2, 0, 0},
"3m ",
"C3v",
TRIGO,
LAUE3M,
},
{ /* 20 */
{0, 0, 2, 3, 1, 1, 3, 2, 0, 0},
"-3m ",
"D3d",
TRIGO,
LAUE3M,
},
{ /* 21 */
{0, 0, 0, 0, 0, 1, 1, 2, 0, 2},
"6 ",
"C6 ",
HEXA,
LAUE6M,
},
{ /* 22 */
{2, 0, 0, 1, 0, 1, 0, 2, 0, 0},
"-6 ",
"C3h",
HEXA,
LAUE6M,
},
{ /* 23 */
{2, 0, 2, 1, 1, 1, 1, 2, 0, 2},
"6/m ",
"C6h",
HEXA,
LAUE6M,
},
{ /* 24 */
{0, 0, 0, 0, 0, 1, 7, 2, 0, 2},
"622 ",
"D6 ",
HEXA,
LAUE6MMM,
},
{ /* 25 */
{0, 0, 0, 6, 0, 1, 1, 2, 0, 2},
"6mm ",
"C6v",
HEXA,
LAUE6MMM,
},
{ /* 26 */
{2, 0, 0, 4, 0, 1, 3, 2, 0, 0},
"-6m2 ",
"D3h",
HEXA,
LAUE6MMM,
},
{ /* 27 */
{2, 0, 2, 7, 1, 1, 7, 2, 0, 2},
"6/mmm",
"D6h",
HEXA,
LAUE6MMM,
},
{ /* 28 */
{0, 0, 0, 0, 0, 1, 3, 8, 0, 0},
"23 ",
"T ",
CUBIC,
LAUEM3,
},
{ /* 29 */
{0, 0, 8, 3, 1, 1, 3, 8, 0, 0},
"m-3 ",
"Th ",
CUBIC,
LAUEM3,
},
{ /* 30 */
{0, 0, 0, 0, 0, 1, 9, 8, 6, 0},
"432 ",
"O ",
CUBIC,
LAUEM3M,
},
{ /* 31 */
{0, 6, 0, 6, 0, 1, 3, 8, 0, 0},
"-43m ",
"Td ",
CUBIC,
LAUEM3M,
},
{ /* 32 */
{0, 6, 8, 9, 1, 1, 9, 8, 6, 0},
"m-3m ",
"Oh ",
CUBIC,
LAUEM3M,
}
};
static int identity[3][3] = {
{ 1, 0, 0},
{ 0, 1, 0},
{ 0, 0, 1},
};
static int inversion[3][3] = {
{-1, 0, 0},
{ 0,-1, 0},
{ 0, 0,-1},
};
static int rot_axes[][3] = {
{ 1, 0, 0},
{ 0, 1, 0},
{ 0, 0, 1},
{ 0, 1, 1},
{ 1, 0, 1},
{ 1, 1, 0},
{ 0, 1,-1},
{-1, 0, 1},
{ 1,-1, 0},
{ 1, 1, 1}, /* 10 */
{-1, 1, 1},
{ 1,-1, 1},
{ 1, 1,-1},
{ 0, 1, 2},
{ 2, 0, 1},
{ 1, 2, 0},
{ 0, 2, 1},
{ 1, 0, 2},
{ 2, 1, 0},
{ 0,-1, 2}, /* 20 */
{ 2, 0,-1},
{-1, 2, 0},
{ 0,-2, 1},
{ 1, 0,-2},
{-2, 1, 0},
{ 2, 1, 1},
{ 1, 2, 1},
{ 1, 1, 2},
{ 2,-1,-1},
{-1, 2,-1}, /* 30 */
{-1,-1, 2},
{ 2, 1,-1},
{-1, 2, 1},
{ 1,-1, 2},
{ 2,-1, 1}, /* 35 */
{ 1, 2,-1},
{-1, 1, 2},
{ 3, 1, 2},
{ 2, 3, 1},
{ 1, 2, 3}, /* 40 */
{ 3, 2, 1},
{ 1, 3, 2},
{ 2, 1, 3},
{ 3,-1, 2},
{ 2, 3,-1}, /* 45 */
{-1, 2, 3},
{ 3,-2, 1},
{ 1, 3,-2},
{-2, 1, 3},
{ 3,-1,-2}, /* 50 */
{-2, 3,-1},
{-1,-2, 3},
{ 3,-2,-1},
{-1, 3,-2},
{-2,-1, 3}, /* 55 */
{ 3, 1,-2},
{-2, 3, 1},
{ 1,-2, 3},
{ 3, 2,-1},
{-1, 3, 2}, /* 60 */
{ 2,-1, 3},
{ 1, 1, 3},
{-1, 1, 3},
{ 1,-1, 3},
{-1,-1, 3}, /* 65 */
{ 1, 3, 1},
{-1, 3, 1},
{ 1, 3,-1},
{-1, 3,-1},
{ 3, 1, 1}, /* 70 */
{ 3, 1,-1},
{ 3,-1, 1},
{ 3,-1,-1},
};
static int get_pointgroup_number_by_rotations(SPGCONST int rotations[][3][3],
const int num_rotations);
static int get_pointgroup_number(SPGCONST PointSymmetry * pointsym);
static int get_pointgroup_class_table(int table[10],
SPGCONST PointSymmetry * pointsym);
static int get_rotation_type(SPGCONST int rot[3][3]);
static int get_rotation_axis(SPGCONST int rot[3][3]);
static int get_orthogonal_axis(int ortho_axes[],
SPGCONST int proper_rot[3][3],
const int rot_order);
static int laue2m(int axes[3],
SPGCONST PointSymmetry * pointsym);
#ifdef SPGDEBUG
static int lauemmm(int axes[3],
SPGCONST PointSymmetry * pointsym);
static int laue4m(int axes[3],
SPGCONST PointSymmetry * pointsym);
static int laue4mmm(int axes[3],
SPGCONST PointSymmetry * pointsym);
static int laue3(int axes[3],
SPGCONST PointSymmetry * pointsym);
static int laue3m(int axes[3],
SPGCONST PointSymmetry * pointsym);
static int lauem3m(int axes[3],
SPGCONST PointSymmetry * pointsym);
#endif
static int laue_one_axis(int axes[3],
SPGCONST PointSymmetry * pointsym,
const int rot_order);
static int lauennn(int axes[3],
SPGCONST PointSymmetry * pointsym,
const int rot_order);
static int get_axes(int axes[3],
const Laue laue,
SPGCONST PointSymmetry * pointsym);
static void get_proper_rotation(int prop_rot[3][3],
SPGCONST int rot[3][3]);
static void set_transformation_matrix(int tmat[3][3],
const int axes[3]);
static int is_exist_axis(const int axis_vec[3], const int axis_index);
static void sort_axes(int axes[3]);
/* Retrun pointgroup.number = 0 if failed */
Pointgroup ptg_get_transformation_matrix(int transform_mat[3][3],
SPGCONST int rotations[][3][3],
const int num_rotations)
{
int i, j, pg_num;
int axes[3];
PointSymmetry pointsym;
Pointgroup pointgroup;
debug_print("ptg_get_transformation_matrix:\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
transform_mat[i][j] = 0;
}
}
pg_num = get_pointgroup_number_by_rotations(rotations, num_rotations);
if (pg_num > 0) {
pointgroup = ptg_get_pointgroup(pg_num);
pointsym = ptg_get_pointsymmetry(rotations, num_rotations);
get_axes(axes, pointgroup.laue, &pointsym);
set_transformation_matrix(transform_mat, axes);
} else {
warning_print("spglib: No point group was found ");
warning_print("(line %d, %s).\n", __LINE__, __FILE__);
pointgroup.number = 0;
}
return pointgroup;
}
Pointgroup ptg_get_pointgroup(const int pointgroup_number)
{
int i;
Pointgroup pointgroup;
PointgroupType pointgroup_type;
pointgroup.number = pointgroup_number;
pointgroup_type = pointgroup_data[pointgroup_number];
memcpy(pointgroup.symbol, pointgroup_type.symbol, 6);
memcpy(pointgroup.schoenflies, pointgroup_type.schoenflies, 4);
for (i = 0; i < 5; i++) {
if (pointgroup.symbol[i] == ' ') {pointgroup.symbol[i] = '\0';}
}
for (i = 0; i < 3; i++) {
if (pointgroup.schoenflies[i] == ' ') {pointgroup.schoenflies[i] = '\0';}
}
pointgroup.holohedry = pointgroup_type.holohedry;
pointgroup.laue = pointgroup_type.laue;
debug_print("ptg_get_pointgroup: %s\n", pointgroup_type.symbol);
return pointgroup;
}
PointSymmetry ptg_get_pointsymmetry(SPGCONST int rotations[][3][3],
const int num_rotations)
{
int i, j;
PointSymmetry pointsym;
pointsym.size = 0;
for (i = 0; i < num_rotations; i++) {
for (j = 0; j < pointsym.size; j++) {
if (mat_check_identity_matrix_i3(rotations[i], pointsym.rot[j])) {
goto escape;
}
}
mat_copy_matrix_i3(pointsym.rot[pointsym.size], rotations[i]);
pointsym.size++;
escape:
;
}
return pointsym;
}
static int get_pointgroup_number_by_rotations(SPGCONST int rotations[][3][3],
const int num_rotations)
{
PointSymmetry pointsym;
pointsym = ptg_get_pointsymmetry(rotations, num_rotations);
return get_pointgroup_number(&pointsym);
}
static int get_pointgroup_number(SPGCONST PointSymmetry * pointsym)
{
int i, j, pg_num, counter;
int table[10];
PointgroupType pointgroup_type;
debug_print("get_pointgroup_number:");
pg_num = 0;
/* Get list of point symmetry operations */
if (! get_pointgroup_class_table(table, pointsym)) {
goto end;
}
for (i = 1; i < 33; i++) {
counter = 0;
pointgroup_type = pointgroup_data[i];
for (j = 0; j < 10; j++) {
if (pointgroup_type.table[j] == table[j]) {counter++;}
}
if (counter == 10) {
pg_num = i;
break;
}
}
end:
debug_print(" %d\n", pg_num);
return pg_num;
}
static int get_pointgroup_class_table(int table[10],
SPGCONST PointSymmetry * pointsym)
{
/* Look-up table */
/* Operation -6 -4 -3 -2 -1 1 2 3 4 6 */
/* Trace - 2 -1 0 1 -3 3 -1 0 1 2 */
/* Determinant -1 -1 -1 -1 -1 1 1 1 1 1 */
/* table[0] = -6 axis */
/* table[1] = -4 axis */
/* table[2] = -3 axis */
/* table[3] = -2 axis */
/* table[4] = -1 axis */
/* table[5] = 1 axis */
/* table[6] = 2 axis */
/* table[7] = 3 axis */
/* table[8] = 4 axis */
/* table[9] = 6 axis */
int i, rot_type;
for (i = 0; i < 10; i++) { table[i] = 0; }
for (i = 0; i < pointsym->size; i++) {
rot_type = get_rotation_type(pointsym->rot[i]);
if (rot_type == -1) {
goto err;
} else {
table[rot_type]++;
}
}
return 1;
err:
warning_print("spglib: No point group symbol found ");
warning_print("(line %d, %s).\n", __LINE__, __FILE__);
return 0;
}
static int get_rotation_type(SPGCONST int rot[3][3])
{
int rot_type;
if (mat_get_determinant_i3(rot) == -1) {
switch (mat_get_trace_i3(rot)) {
case -2: /* -6 */
rot_type = 0;
break;
case -1: /* -4 */
rot_type = 1;
break;
case 0: /* -3 */
rot_type = 2;
break;
case 1: /* -2 */
rot_type = 3;
break;
case -3: /* -1 */
rot_type = 4;
break;
default:
rot_type = -1;
break;
}
} else {
switch (mat_get_trace_i3(rot)) {
case 3: /* 1 */
rot_type = 5;
break;
case -1: /* 2 */
rot_type = 6;
break;
case 0: /* 3 */
rot_type = 7;
break;
case 1: /* 4 */
rot_type = 8;
break;
case 2: /* 6 */
rot_type = 9;
break;
default:
rot_type = -1;
break;
}
}
return rot_type;
}
static int get_axes(int axes[3],
const Laue laue,
SPGCONST PointSymmetry * pointsym)
{
switch (laue) {
case LAUE1:
axes[0] = 0;
axes[1] = 1;
axes[2] = 2;
break;
case LAUE2M:
laue2m(axes, pointsym);
break;
case LAUEMMM:
lauennn(axes, pointsym, 2);
break;
case LAUE4M:
laue_one_axis(axes, pointsym, 4);
break;
case LAUE4MMM:
laue_one_axis(axes, pointsym, 4);
break;
case LAUE3:
laue_one_axis(axes, pointsym, 3);
break;
case LAUE3M:
laue_one_axis(axes, pointsym, 3);
break;
case LAUE6M:
laue_one_axis(axes, pointsym, 3);
break;
case LAUE6MMM:
laue_one_axis(axes, pointsym, 3);
break;
case LAUEM3:
lauennn(axes, pointsym, 2);
break;
case LAUEM3M:
lauennn(axes, pointsym, 4);
break;
default:
break;
}
return 1;
}
static int laue2m(int axes[3],
SPGCONST PointSymmetry * pointsym)
{
int i, num_ortho_axis, norm, min_norm, is_found, tmpval;
int prop_rot[3][3], t_mat[3][3];
int ortho_axes[NUM_ROT_AXES];
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search two-fold rotation */
if (! (mat_get_trace_i3(prop_rot) == -1)) {
continue;
}
/* The first axis */
axes[1] = get_rotation_axis(prop_rot);
break;
}
/* The second axis */
num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, 2);
if (! num_ortho_axis) { goto err; }
min_norm = 8;
is_found = 0;
for (i = 0; i < num_ortho_axis; i++) {
norm = mat_norm_squared_i3(rot_axes[ortho_axes[i]]);
if (norm < min_norm - ZERO_PREC) {
min_norm = norm;
axes[0] = ortho_axes[i];
is_found = 1;
}
}
if (! is_found) { goto err; }
/* The third axis */
min_norm = 8;
is_found = 0;
for (i = 0; i < num_ortho_axis; i++) {
norm = mat_norm_squared_i3(rot_axes[ortho_axes[i]]);
if ((norm < min_norm - ZERO_PREC) && (ortho_axes[i] != axes[0])) {
min_norm = norm;
axes[2] = ortho_axes[i];
is_found = 1;
}
}
if (! is_found) { goto err; }
set_transformation_matrix(t_mat, axes);
if (mat_get_determinant_i3(t_mat) < 0) {
tmpval = axes[0];
axes[0] = axes[2];
axes[2] = tmpval;
}
return 1;
err:
return 0;
}
#ifdef SPGDEBUG
static int lauemmm(int axes[3],
SPGCONST PointSymmetry * pointsym)
{
int i, count, axis;
int prop_rot[3][3];
for (i = 0; i < 3; i++) { axes[i] = -1; }
count = 0;
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search two-fold rotation */
if (! (mat_get_trace_i3(prop_rot) == -1)) {
continue;
}
axis = get_rotation_axis(prop_rot);
if (! ((axis == axes[0]) ||
(axis == axes[1]) ||
(axis == axes[2]))) {
axes[count] = axis;
count++;
}
}
sort_axes(axes);
return 1;
}
static int laue4m(int axes[3],
SPGCONST PointSymmetry * pointsym)
{
int i, num_ortho_axis, norm, min_norm, is_found, tmpval;
int axis_vec[3];
int prop_rot[3][3], t_mat[3][3];
int ortho_axes[NUM_ROT_AXES];
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search foud-fold rotation */
if ( mat_get_trace_i3(prop_rot) == 1) {
/* The first axis */
axes[2] = get_rotation_axis(prop_rot);
break;
}
}
/* The second axis */
num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, 4);
if (! num_ortho_axis) { goto err; }
min_norm = 8;
is_found = 0;
for (i = 0; i < num_ortho_axis; i++) {
norm = mat_norm_squared_i3(rot_axes[ortho_axes[i]]);
if (norm < min_norm - ZERO_PREC) {
min_norm = norm;
axes[0] = ortho_axes[i];
is_found = 1;
}
}
if (! is_found) { goto err; }
/* The third axis */
mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]);
is_found = 0;
for (i = 0; i < NUM_ROT_AXES; i++) {
if (is_exist_axis(axis_vec, i)) {
is_found = 1;
axes[1] = i;
break;
}
}
if (! is_found) { goto err; }
set_transformation_matrix(t_mat, axes);
if (mat_get_determinant_i3(t_mat) < 0) {
tmpval = axes[0];
axes[0] = axes[1];
axes[1] = tmpval;
}
return 1;
err:
return 0;
}
static int laue4mmm(int axes[3],
SPGCONST PointSymmetry * pointsym)
{
int i, is_found, tmpval, axis;
int prop_rot[3][3], prop_rot2[3][3], t_mat[3][3];
int axis_vec[3];
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search foud-fold rotation */
if (mat_get_trace_i3(prop_rot) == 1) {
/* The first axis */
axes[2] = get_rotation_axis(prop_rot);
break;
}
}
is_found = 0;
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot2, pointsym->rot[i]);
/* Search two-fold rotation */
if (! (mat_get_trace_i3(prop_rot2) == -1)) {
continue;
}
/* The second axis */
axis = get_rotation_axis(prop_rot2);
if (! (axis == axes[2])) {
axes[0] = axis;
is_found = 1;
break;
}
}
if (! is_found) { goto err; }
/* The third axis */
mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]);
is_found = 0;
for (i = 0; i < NUM_ROT_AXES; i++) {
if (is_exist_axis(axis_vec, i)) {
is_found = 1;
axes[1] = i;
break;
}
}
if (! is_found) { goto err; }
set_transformation_matrix(t_mat, axes);
if (mat_get_determinant_i3(t_mat) < 0) {
tmpval = axes[0];
axes[0] = axes[1];
axes[1] = tmpval;
}
return 1;
err:
return 0;
}
static int laue3(int axes[3],
SPGCONST PointSymmetry * pointsym)
{
int i, num_ortho_axis, norm, min_norm, is_found, tmpval;
int prop_rot[3][3], t_mat[3][3];
int axis_vec[3];
int ortho_axes[NUM_ROT_AXES];
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search thee-fold rotation */
if (mat_get_trace_i3(prop_rot) == 0) {
/* The first axis */
axes[2] = get_rotation_axis(prop_rot);
break;
}
}
/* The second axis */
num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, 3);
if (! num_ortho_axis) { goto err; }
min_norm = 8;
is_found = 0;
for (i = 0; i < num_ortho_axis; i++) {
norm = mat_norm_squared_i3(rot_axes[ortho_axes[i]]);
if (norm < min_norm - ZERO_PREC) {
min_norm = norm;
axes[0] = ortho_axes[i];
is_found = 1;
}
}
if (! is_found) { goto err; }
/* The third axis */
mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]);
is_found = 0;
for (i = 0; i < NUM_ROT_AXES; i++) {
is_found = is_exist_axis(axis_vec, i);
if (is_found == 1) {
axes[1] = i;
break;
}
if (is_found == -1) {
axes[1] = i + NUM_ROT_AXES;
break;
}
}
if (! is_found) { goto err; }
set_transformation_matrix(t_mat, axes);
if (mat_get_determinant_i3(t_mat) < 0) {
tmpval = axes[0];
axes[0] = axes[1];
axes[1] = tmpval;
}
return 1;
err:
return 0;
}
static int laue3m(int axes[3],
SPGCONST PointSymmetry * pointsym)
{
int i, is_found, tmpval, axis;
int prop_rot[3][3], prop_rot2[3][3], t_mat[3][3];
int axis_vec[3];
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search three-fold rotation */
if (mat_get_trace_i3(prop_rot) == 0) {
/* The first axis */
axes[2] = get_rotation_axis(prop_rot);
debug_print("laue3m prop_rot\n");
debug_print_matrix_i3(prop_rot);
break;
}
}
is_found = 0;
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot2, pointsym->rot[i]);
/* Search two-fold rotation */
if (! (mat_get_trace_i3(prop_rot2) == -1)) {
continue;
}
/* The second axis */
axis = get_rotation_axis(prop_rot2);
if (! (axis == axes[2])) {
axes[0] = axis;
is_found = 1;
break;
}
}
if (! is_found) { goto err; }
/* The third axis */
mat_multiply_matrix_vector_i3(axis_vec, prop_rot, rot_axes[axes[0]]);
is_found = 0;
for (i = 0; i < NUM_ROT_AXES; i++) {
is_found = is_exist_axis(axis_vec, i);
if (is_found == 1) {
axes[1] = i;
break;
}
if (is_found == -1) {
axes[1] = i + NUM_ROT_AXES;
break;
}
}
if (! is_found) { goto err; }
set_transformation_matrix(t_mat, axes);
if (mat_get_determinant_i3(t_mat) < 0) {
tmpval = axes[0];
axes[0] = axes[1];
axes[1] = tmpval;
}
return 1;
err:
return 0;
}
static int lauem3m(int axes[3],
SPGCONST PointSymmetry * pointsym)
{
int i, count, axis;
int prop_rot[3][3];
for (i = 0; i < 3; i++) { axes[i] = -1; }
count = 0;
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search four-fold rotation */
if (! (mat_get_trace_i3(prop_rot) == 1)) {
continue;
}
axis = get_rotation_axis(prop_rot);
if (! ((axis == axes[0]) ||
(axis == axes[1]) ||
(axis == axes[2]))) {
axes[count] = axis;
count++;
}
}
sort_axes(axes);
return 1;
}
#endif
static int laue_one_axis(int axes[3],
SPGCONST PointSymmetry * pointsym,
const int rot_order)
{
int i, j, num_ortho_axis, det, is_found, tmpval;
int axis_vec[3], tmp_axes[3];
int prop_rot[3][3], t_mat[3][3];
int ortho_axes[NUM_ROT_AXES];
debug_print("laue_one_axis with rot_order %d\n", rot_order);
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search foud-fold rotation */
if (rot_order == 4) {
if (mat_get_trace_i3(prop_rot) == 1) {
/* The first axis */
axes[2] = get_rotation_axis(prop_rot);
break;
}
}
/* Search three-fold rotation */
if (rot_order == 3) {
if (mat_get_trace_i3(prop_rot) == 0) {
/* The first axis */
axes[2] = get_rotation_axis(prop_rot);
break;
}
}
}
/* Candidates of the second axis */
num_ortho_axis = get_orthogonal_axis(ortho_axes, prop_rot, rot_order);
if (! num_ortho_axis) { goto err; }
tmp_axes[1] = -1;
tmp_axes[2] = axes[2];
for (i = 0; i < num_ortho_axis; i++) {
is_found = 0;
tmp_axes[0] = ortho_axes[i];
mat_multiply_matrix_vector_i3(axis_vec,
prop_rot,
rot_axes[tmp_axes[0]]);
for (j = 0; j < num_ortho_axis; j++) {
is_found = is_exist_axis(axis_vec, ortho_axes[j]);
if (is_found == 1) {
tmp_axes[1] = ortho_axes[j];
break;
}
if (is_found == -1) {
tmp_axes[1] = ortho_axes[j] + NUM_ROT_AXES;
break;
}
}
if (!is_found) { continue; }
set_transformation_matrix(t_mat, tmp_axes);
det = abs(mat_get_determinant_i3(t_mat));
if (det < 4) { /* to avoid F-center choice det=4 */
axes[0] = tmp_axes[0];
axes[1] = tmp_axes[1];
goto end;
}
}
err: /* axes are not correctly found. */
warning_print("spglib: Secondary axis is not found.");
warning_print("(line %d, %s).\n", __LINE__, __FILE__);
return 0;
end:
set_transformation_matrix(t_mat, axes);
if (mat_get_determinant_i3(t_mat) < 0) {
tmpval = axes[0];
axes[0] = axes[1];
axes[1] = tmpval;
}
debug_print("axes[0] = %d\n", axes[0]);
debug_print("axes[1] = %d\n", axes[1]);
debug_print("axes[2] = %d\n", axes[2]);
return 1;
}
static int lauennn(int axes[3],
SPGCONST PointSymmetry * pointsym,
const int rot_order)
{
int i, count, axis;
int prop_rot[3][3];
for (i = 0; i < 3; i++) {
axes[i] = -1;
}
count = 0;
for (i = 0; i < pointsym->size; i++) {
get_proper_rotation(prop_rot, pointsym->rot[i]);
/* Search two- or four-fold rotation */
if ((mat_get_trace_i3(prop_rot) == -1 && rot_order == 2) ||
(mat_get_trace_i3(prop_rot) == 1 && rot_order == 4)) {
axis = get_rotation_axis(prop_rot);
if (! ((axis == axes[0]) ||
(axis == axes[1]) ||
(axis == axes[2]))) {
axes[count] = axis;
count++;
}
}
}
sort_axes(axes);
return 1;
}
static int get_rotation_axis(SPGCONST int proper_rot[3][3])
{
int i, axis = -1;
int vec[3];
/* No specific axis for I and -I */
if (mat_check_identity_matrix_i3(proper_rot, identity)) {
goto end;
}
/* Look for eigenvector = rotation axis */
for (i = 0; i < NUM_ROT_AXES; i++) {
mat_multiply_matrix_vector_i3(vec, proper_rot, rot_axes[i]);
if (vec[0] == rot_axes[i][0] &&
vec[1] == rot_axes[i][1] &&
vec[2] == rot_axes[i][2]) {
axis = i;
break;
}
}
end:
#ifdef SPGDEBUG
if (axis == -1) {
printf("rotation axis cound not found.\n");
}
#endif
return axis;
}
static int get_orthogonal_axis(int ortho_axes[],
SPGCONST int proper_rot[3][3],
const int rot_order)
{
int i, num_ortho_axis;
int vec[3];
int sum_rot[3][3], rot[3][3];
num_ortho_axis = 0;
mat_copy_matrix_i3(sum_rot, identity);
mat_copy_matrix_i3(rot, identity);
for (i = 0; i < rot_order - 1; i++) {
mat_multiply_matrix_i3(rot, proper_rot, rot);
mat_add_matrix_i3(sum_rot, rot, sum_rot);
}
for (i = 0; i < NUM_ROT_AXES; i++) {
mat_multiply_matrix_vector_i3(vec, sum_rot, rot_axes[i]);
if (vec[0] == 0 &&
vec[1] == 0 &&
vec[2] == 0) {
ortho_axes[num_ortho_axis] = i;
num_ortho_axis++;
}
}
return num_ortho_axis;
}
static void get_proper_rotation(int prop_rot[3][3],
SPGCONST int rot[3][3])
{
if (mat_get_determinant_i3(rot) == -1) {
mat_multiply_matrix_i3(prop_rot, inversion, rot);
} else {
mat_copy_matrix_i3(prop_rot, rot);
}
}
static void set_transformation_matrix(int tmat[3][3],
const int axes[3])
{
int i, j, s[3];
for (i = 0; i < 3; i++) {
if (axes[i] < NUM_ROT_AXES) {
s[i] = 1;
} else {
s[i] = -1; /* axes[i] + NUM_ROT_AXES means improper rotation. */
}
}
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
tmat[i][j] = s[j] * rot_axes[axes[j]%NUM_ROT_AXES][i];
}
}
}
static int is_exist_axis(const int axis_vec[3], const int axis_index)
{
if ((axis_vec[0] == rot_axes[axis_index][0]) &&
(axis_vec[1] == rot_axes[axis_index][1]) &&
(axis_vec[2] == rot_axes[axis_index][2])) { return 1; }
if ((axis_vec[0] == -rot_axes[axis_index][0]) &&
(axis_vec[1] == -rot_axes[axis_index][1]) &&
(axis_vec[2] == -rot_axes[axis_index][2])) { return -1; }
return 0;
}
static void sort_axes(int axes[3])
{
int axis;
int t_mat[3][3];
if (axes[1] > axes[2] + ZERO_PREC) {
axis = axes[1];
axes[1] = axes[2];
axes[2] = axis;
}
if (axes[0] > axes[1] + ZERO_PREC) {
axis = axes[0];
axes[0] = axes[1];
axes[1] = axis;
}
if (axes[1] > axes[2] + ZERO_PREC) {
axis = axes[1];
axes[1] = axes[2];
axes[2] = axis;
}
set_transformation_matrix(t_mat, axes);
if (mat_get_determinant_i3(t_mat) < 0) {
axis = axes[1];
axes[1] = axes[2];
axes[2] = axis;
}
}