mirror of https://github.com/phonopy/phonopy.git
1312 lines
28 KiB
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;
|
|
}
|
|
}
|